libsigrok-0.3.0/0000755000175000017500000000000012332246734010506 500000000000000libsigrok-0.3.0/session_file.c0000644000175000017500000003312012332246667013260 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen * * 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 . */ #include #include #include #include #include #include #include #include #include #include "config.h" /* Needed for PACKAGE_VERSION and others. */ #include "libsigrok.h" #include "libsigrok-internal.h" /** @cond PRIVATE */ #define LOG_PREFIX "session-file" /** @endcond */ /** * @file * * Loading and saving libsigrok session files. */ /** * @addtogroup grp_session * * @{ */ extern struct sr_session *session; extern SR_PRIV struct sr_dev_driver session_driver; /** @private */ SR_PRIV int sr_sessionfile_check(const char *filename) { struct stat st; struct zip *archive; struct zip_file *zf; struct zip_stat zs; int version, ret; char s[11]; if (!filename) return SR_ERR_ARG; if (stat(filename, &st) == -1) { sr_err("Couldn't stat %s: %s", filename, strerror(errno)); return SR_ERR; } 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: no version found."); return SR_ERR; } if ((ret = zip_fread(zf, s, 10)) == -1) return SR_ERR; zip_fclose(zf); s[ret] = 0; version = strtoull(s, NULL, 10); if (version > 2) { sr_dbg("Cannot handle sigrok session file version %d.", version); return SR_ERR; } sr_spew("Detected sigrok session file version %d.", version); /* read "metadata" */ if (zip_stat(archive, "metadata", 0, &zs) == -1) { sr_dbg("Not a valid sigrok session file."); 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_channel *ch; int ret, channelnum, devcnt, i, j; uint64_t tmp_u64, total_channels, enabled_channels, p; char **sections, **keys, *metafile, *val; char channelname[SR_MAX_CHANNELNAME_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; } zf = zip_fopen_index(archive, zs.index, 0); zip_fread(zf, metafile, zs.size); zip_fclose(zf); kf = g_key_file_new(); if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, NULL)) { sr_dbg("Failed to parse metadata."); return SR_ERR; } sr_session_new(); devcnt = 0; capturefiles = g_ptr_array_new_with_free_func(g_free); sections = g_key_file_get_groups(kf, NULL); for (i = 0; sections[i]; i++) { if (!strcmp(sections[i], "global")) /* nothing really interesting in here yet */ continue; if (!strncmp(sections[i], "device ", 7)) { /* device section */ sdi = NULL; enabled_channels = total_channels = 0; keys = g_key_file_get_keys(kf, sections[i], NULL, NULL); for (j = 0; keys[j]; j++) { val = g_key_file_get_string(kf, sections[i], keys[j], NULL); if (!strcmp(keys[j], "capturefile")) { sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, NULL, NULL, NULL); sdi->driver = &session_driver; if (devcnt == 0) /* first device, init the driver */ sdi->driver->init(NULL); sr_dev_open(sdi); sr_session_dev_add(sdi); sdi->driver->config_set(SR_CONF_SESSIONFILE, g_variant_new_string(filename), sdi, NULL); sdi->driver->config_set(SR_CONF_CAPTUREFILE, g_variant_new_string(val), sdi, NULL); g_ptr_array_add(capturefiles, val); } else if (!strcmp(keys[j], "samplerate")) { sr_parse_sizestring(val, &tmp_u64); sdi->driver->config_set(SR_CONF_SAMPLERATE, g_variant_new_uint64(tmp_u64), sdi, NULL); } else if (!strcmp(keys[j], "unitsize")) { tmp_u64 = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_CAPTURE_UNITSIZE, g_variant_new_uint64(tmp_u64), sdi, NULL); } else if (!strcmp(keys[j], "total probes")) { total_channels = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_NUM_LOGIC_CHANNELS, g_variant_new_uint64(total_channels), sdi, NULL); for (p = 0; p < total_channels; p++) { snprintf(channelname, SR_MAX_CHANNELNAME_LEN, "%" PRIu64, p); if (!(ch = sr_channel_new(p, SR_CHANNEL_LOGIC, TRUE, channelname))) return SR_ERR; sdi->channels = g_slist_append(sdi->channels, ch); } } else if (!strncmp(keys[j], "probe", 5)) { if (!sdi) continue; enabled_channels++; tmp_u64 = strtoul(keys[j]+5, NULL, 10); /* sr_session_save() */ sr_dev_channel_name_set(sdi, tmp_u64 - 1, val); } else if (!strncmp(keys[j], "trigger", 7)) { channelnum = strtoul(keys[j]+7, NULL, 10); sr_dev_trigger_set(sdi, channelnum, val); } } g_strfreev(keys); /* Disable channels not specifically listed. */ if (total_channels) for (p = enabled_channels; p < total_channels; p++) sr_dev_channel_enable(sdi, p, FALSE); } devcnt++; } g_strfreev(sections); g_key_file_free(kf); return SR_OK; } /** * Save the current session to the specified file. * * @param filename The name of the filename to save the current session as. * Must not be NULL. * @param sdi The device instance from which the data was captured. * @param buf The data to be saved. * @param unitsize The number of bytes per sample. * @param units The number of samples. * * @retval SR_OK Success * @retval SR_ERR_ARG Invalid arguments * @retval SR_ERR Other errors * * @since 0.2.0 */ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, unsigned char *buf, int unitsize, int units) { struct sr_channel *ch; GSList *l; GVariant *gvar; uint64_t samplerate; int cnt, ret; char **channel_names; samplerate = 0; if (sr_dev_has_option(sdi, SR_CONF_SAMPLERATE)) { if (sr_config_get(sdi->driver, sdi, NULL, SR_CONF_SAMPLERATE, &gvar) == SR_OK) { samplerate = g_variant_get_uint64(gvar); g_variant_unref(gvar); } } channel_names = g_malloc0(sizeof(char *) * (g_slist_length(sdi->channels) + 1)); cnt = 0; for (l = sdi->channels; l; l = l->next) { ch = l->data; if (ch->type != SR_CHANNEL_LOGIC) continue; if (ch->enabled != TRUE) continue; if (!ch->name) continue; /* Just borrowing the ptr. */ channel_names[cnt++] = ch->name; } if ((ret = sr_session_save_init(filename, samplerate, channel_names)) != SR_OK) return ret; ret = sr_session_append(filename, buf, unitsize, units); return ret; } /** * Initialize a saved session file. * * @param filename The name of the filename to save the current session as. * Must not be NULL. * @param samplerate The samplerate to store for this session. * @param channels A NULL-terminated array of strings containing the names * of all the channels active in this session. * * @retval SR_OK Success * @retval SR_ERR_ARG Invalid arguments * @retval SR_ERR Other errors * * @since 0.3.0 */ SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, char **channels) { FILE *meta; struct zip *zipfile; struct zip_source *versrc, *metasrc; int tmpfile, cnt, ret, i; char version[1], metafile[32], *s; if (!filename) { sr_err("%s: filename was NULL", __func__); return SR_ERR_ARG; } /* Quietly delete it first, libzip wants replace ops otherwise. */ unlink(filename); if (!(zipfile = zip_open(filename, ZIP_CREATE, &ret))) return SR_ERR; /* "version" */ version[0] = '2'; if (!(versrc = zip_source_buffer(zipfile, version, 1, 0))) return SR_ERR; if (zip_add(zipfile, "version", versrc) == -1) { sr_info("error saving version into zipfile: %s", zip_strerror(zipfile)); return SR_ERR; } /* init "metadata" */ strcpy(metafile, "sigrok-meta-XXXXXX"); if ((tmpfile = g_mkstemp(metafile)) == -1) return SR_ERR; close(tmpfile); meta = g_fopen(metafile, "wb"); fprintf(meta, "[global]\n"); fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION); /* metadata */ fprintf(meta, "[device 1]\n"); /* metadata */ fprintf(meta, "capturefile = logic-1\n"); cnt = 0; for (i = 0; channels[i]; i++) cnt++; fprintf(meta, "total probes = %d\n", cnt); s = sr_samplerate_string(samplerate); fprintf(meta, "samplerate = %s\n", s); g_free(s); for (i = 0; channels[i]; i++) fprintf(meta, "probe%d = %s\n", i + 1, channels[i]); fclose(meta); if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) { unlink(metafile); return SR_ERR; } if (zip_add(zipfile, "metadata", metasrc) == -1) { unlink(metafile); return SR_ERR; } if ((ret = zip_close(zipfile)) == -1) { sr_info("error saving zipfile: %s", zip_strerror(zipfile)); unlink(metafile); return SR_ERR; } unlink(metafile); return SR_OK; } /** * Append data to an existing session file. * * The session file must have been created with sr_session_save_init() * or sr_session_save() beforehand. * * @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. * * @retval SR_OK Success * @retval SR_ERR_ARG Invalid arguments * @retval SR_ERR Other errors * * @since 0.3.0 */ 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; struct zip_file *zf; struct zip_stat zs; struct zip_source *metasrc; GKeyFile *kf; GError *error; gsize len; int chunk_num, next_chunk_num, tmpfile, ret, i; const char *entry_name; char *metafile, tmpname[32], chunkname[16]; 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; metafile = g_malloc(zs.size); zf = zip_fopen_index(archive, zs.index, 0); zip_fread(zf, metafile, zs.size); zip_fclose(zf); /* * If the file was only initialized but doesn't yet have any * data it in, it won't have a unitsize field in metadata yet. */ error = NULL; kf = g_key_file_new(); if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, &error)) { sr_err("Failed to parse metadata: %s.", error->message); return SR_ERR; } g_free(metafile); tmpname[0] = '\0'; if (!g_key_file_has_key(kf, "device 1", "unitsize", &error)) { if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { sr_err("Failed to check unitsize key: %s", error ? error->message : "?"); return SR_ERR; } /* Add unitsize field. */ g_key_file_set_integer(kf, "device 1", "unitsize", unitsize); metafile = g_key_file_to_data(kf, &len, &error); strcpy(tmpname, "sigrok-meta-XXXXXX"); if ((tmpfile = g_mkstemp(tmpname)) == -1) return SR_ERR; if (write(tmpfile, metafile, len) < 0) { sr_dbg("Failed to create new metadata: %s", strerror(errno)); g_free(metafile); unlink(tmpname); return SR_ERR; } close(tmpfile); if (!(metasrc = zip_source_file(archive, tmpname, 0, -1))) { sr_err("Failed to create zip source for metadata."); g_free(metafile); unlink(tmpname); return SR_ERR; } if (zip_replace(archive, zs.index, metasrc) == -1) { sr_err("Failed to replace metadata file."); g_free(metafile); unlink(tmpname); return SR_ERR; } g_free(metafile); } g_key_file_free(kf); 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'."); unlink(tmpname); 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))) { unlink(tmpname); return SR_ERR; } if (zip_add(archive, chunkname, logicsrc) == -1) { unlink(tmpname); return SR_ERR; } if ((ret = zip_close(archive)) == -1) { sr_info("error saving session file: %s", zip_strerror(archive)); unlink(tmpname); return SR_ERR; } unlink(tmpname); return SR_OK; } /** @} */ libsigrok-0.3.0/hardware/0000755000175000017500000000000012332246734012303 500000000000000libsigrok-0.3.0/hardware/norma-dmm/0000755000175000017500000000000012332246734014172 500000000000000libsigrok-0.3.0/hardware/norma-dmm/protocol.h0000644000175000017500000000466312332246667016142 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Matthias Heidbrink * * 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 . */ #ifndef LIBSIGROK_HARDWARE_NORMA_DMM_PROTOCOL_H #define LIBSIGROK_HARDWARE_NORMA_DMM_PROTOCOL_H #include #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "norma-dmm" #define NMADMM_BUFSIZE 256 /** Norma DMM request types (used ones only, the DMMs support about 50). */ enum { NMADMM_REQ_IDN = 0, /**< Request identity */ NMADMM_REQ_STATUS, /**< Request device status (value + ...) */ }; /** Defines requests used to communicate with device. */ struct nmadmm_req { int req_type; /**< Request type. */ const char *req_str; /**< Request string. */ }; /** Strings for requests. */ extern const struct nmadmm_req nmadmm_requests[]; /** Private, per-device-instance driver context. */ struct dev_context { /* Model-specific information */ char *version; /**< Version string */ int type; /**< DM9x0, e.g. 5 = DM950 */ /* Acquisition settings */ uint64_t limit_samples; /**< Target number of samples */ uint64_t limit_msec; /**< Target sampling time */ /* Opaque pointer passed in by frontend. */ void *cb_data; /* Operational state */ int last_req; /**< Last request. */ gboolean last_req_pending; /**< Last request not answered yet. */ int lowbatt; /**< Low battery. 1=low, 2=critical. */ /* Temporary state across callbacks */ uint64_t num_samples; /**< Current #samples. */ GTimer *elapsed_msec; /**< Used for limit_msec */ uint8_t buf[NMADMM_BUFSIZE]; /**< Buffer for read callback */ int buflen; /**< Data len in buf */ }; SR_PRIV int norma_dmm_receive_data(int fd, int revents, void *cb_data); SR_PRIV int xgittoint(char xgit); #endif libsigrok-0.3.0/hardware/norma-dmm/protocol.c0000644000175000017500000002471712332246667016137 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Matthias Heidbrink * * 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 . */ #include "protocol.h" SR_PRIV const struct nmadmm_req nmadmm_requests[] = { { NMADMM_REQ_IDN, "IDN?" }, { NMADMM_REQ_IDN, "STATUS?" }, { 0, NULL }, }; static int nma_send_req(const struct sr_dev_inst *sdi, int req, char *params) { struct sr_serial_dev_inst *serial; struct dev_context *devc; char buf[NMADMM_BUFSIZE]; int len; if (!sdi || !(serial = sdi->conn) || !(devc = sdi->priv)) return SR_ERR_BUG; len = snprintf(buf, sizeof(buf), "%s%s\r\n", nmadmm_requests[req].req_str, params ? params : ""); sr_spew("Sending request: '%s'.", buf); devc->last_req = req; devc->last_req_pending = TRUE; if (serial_write(serial, buf, len) == -1) { sr_err("Unable to send request: %d %s.", errno, strerror(errno)); devc->last_req_pending = FALSE; return SR_ERR; } return SR_OK; } /** * Convert hexadecimal digit to int. * * @param[in] xgit Hexadecimal digit to convert. * @return Int value of xgit (0 on invalid xgit). */ SR_PRIV int xgittoint(char xgit) { if ((xgit >= '0') && (xgit <= '9')) return xgit - '0'; xgit = tolower(xgit); if ((xgit >= 'a') && (xgit <= 'f')) return xgit - 'a'; return 0; } /** * Process received line. It consists of 20 hex digits + \\r\\n, * e.g. '08100400018100400000'. */ static void nma_process_line(const struct sr_dev_inst *sdi) { struct dev_context *devc; int pos, flags; int vt, range; /* Measurement value type, range in device format */ int mmode, devstat; /* Measuring mode, device status */ float value; /* Measured value */ float scale; /* Scaling factor depending on range and function */ struct sr_datafeed_analog analog; struct sr_datafeed_packet packet; devc = sdi->priv; devc->buf[20] = '\0'; sr_spew("Received line '%s'.", devc->buf); /* Check line. */ if (strlen((const char *)devc->buf) != 20) { sr_err("line: Invalid status '%s', must be 20 hex digits.", devc->buf); devc->buflen = 0; return; } for (pos = 0; pos < 20; pos++) { if (!isxdigit(devc->buf[pos])) { sr_err("line: Expected hex digit in '%s' at pos %d!", devc->buf, pos); devc->buflen = 0; return; } } /* Start decoding. */ value = 0.0; scale = 1.0; memset(&analog, 0, sizeof(analog)); /* * The numbers are hex digits, starting from 0. * 0: Keyboard status, currently not interesting. * 1: Central switch status, currently not interesting. * 2: Type of measured value. */ vt = xgittoint(devc->buf[2]); switch (vt) { case 0: analog.mq = SR_MQ_VOLTAGE; break; case 1: analog.mq = SR_MQ_CURRENT; /* 2A */ break; case 2: analog.mq = SR_MQ_RESISTANCE; break; case 3: analog.mq = SR_MQ_CAPACITANCE; break; case 4: analog.mq = SR_MQ_TEMPERATURE; break; case 5: analog.mq = SR_MQ_FREQUENCY; break; case 6: analog.mq = SR_MQ_CURRENT; /* 10A */ break; case 7: analog.mq = SR_MQ_GAIN; /* TODO: Scale factor */ break; case 8: analog.mq = SR_MQ_GAIN; /* Percentage */ scale /= 100.0; break; case 9: analog.mq = SR_MQ_GAIN; /* dB */ scale /= 100.0; break; default: sr_err("Unknown value type: 0x%02x.", vt); break; } /* 3: Measurement range for measured value */ range = xgittoint(devc->buf[3]); switch (vt) { case 0: /* V */ scale *= pow(10.0, range - 5); break; case 1: /* A */ scale *= pow(10.0, range - 7); break; case 2: /* Ω */ scale *= pow(10.0, range - 2); break; case 3: /* F */ scale *= pow(10.0, range - 12); break; case 4: /* °C */ scale *= pow(10.0, range - 1); break; case 5: /* Hz */ scale *= pow(10.0, range - 2); break; // No default, other value types have fixed display format. } /* 5: Sign and 1st digit */ flags = xgittoint(devc->buf[5]); value = (flags & 0x03); if (flags & 0x04) scale *= -1; /* 6-9: 2nd-4th digit */ for (pos = 6; pos < 10; pos++) value = value * 10 + xgittoint(devc->buf[pos]); value *= scale; /* 10: Display counter */ mmode = xgittoint(devc->buf[10]); switch (mmode) { case 0: /* Frequency */ analog.unit = SR_UNIT_HERTZ; break; case 1: /* V TRMS, only type 5 */ analog.unit = SR_UNIT_VOLT; analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS); break; case 2: /* V AC */ analog.unit = SR_UNIT_VOLT; analog.mqflags |= SR_MQFLAG_AC; if (devc->type >= 3) analog.mqflags |= SR_MQFLAG_RMS; break; case 3: /* V DC */ analog.unit = SR_UNIT_VOLT; analog.mqflags |= SR_MQFLAG_DC; break; case 4: /* Ohm */ analog.unit = SR_UNIT_OHM; break; case 5: /* Continuity */ analog.unit = SR_UNIT_BOOLEAN; analog.mq = SR_MQ_CONTINUITY; /* TODO: Continuity handling is a bit odd in libsigrok. */ break; case 6: /* Degree Celsius */ analog.unit = SR_UNIT_CELSIUS; break; case 7: /* Capacity */ analog.unit = SR_UNIT_FARAD; break; case 8: /* Current DC */ analog.unit = SR_UNIT_AMPERE; analog.mqflags |= SR_MQFLAG_DC; break; case 9: /* Current AC */ analog.unit = SR_UNIT_AMPERE; analog.mqflags |= SR_MQFLAG_AC; if (devc->type >= 3) analog.mqflags |= SR_MQFLAG_RMS; break; case 0xa: /* Current TRMS, only type 5 */ analog.unit = SR_UNIT_AMPERE; analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS); break; case 0xb: /* Diode */ analog.unit = SR_UNIT_VOLT; analog.mqflags |= (SR_MQFLAG_DIODE | SR_MQFLAG_DC); break; default: sr_err("Unknown mmode: 0x%02x.", mmode); break; } /* 11: Device status */ devstat = xgittoint(devc->buf[11]); switch (devstat) { case 1: /* Normal measurement */ break; case 2: /* Input loop (limit, reference values) */ break; case 3: /* TRANS/SENS */ break; case 4: /* Error */ sr_err("Device error. Fuse?"); /* TODO: Really abort? */ devc->buflen = 0; return; /* Cannot continue. */ default: sr_err("Unknown device status: 0x%02x", devstat); break; } /* 12-19: Flags and display symbols */ /* 12, 13 */ flags = (xgittoint(devc->buf[12]) << 8) | xgittoint(devc->buf[13]); /* 0x80: PRINT TODO: Stop polling when discovered? */ /* 0x40: EXTR */ if (analog.mq == SR_MQ_CONTINUITY) { if (flags & 0x20) value = 1.0; /* Beep */ else value = 0.0; } /* 0x10: AVG */ /* 0x08: Diode */ if (flags & 0x04) /* REL */ analog.mqflags |= SR_MQFLAG_RELATIVE; /* 0x02: SHIFT */ if (flags & 0x01) /* % */ analog.unit = SR_UNIT_PERCENTAGE; /* 14, 15 */ flags = (xgittoint(devc->buf[14]) << 8) | xgittoint(devc->buf[15]); if (!(flags & 0x80)) /* MAN: Manual range */ analog.mqflags |= SR_MQFLAG_AUTORANGE; if (flags & 0x40) /* LOBATT1: Low battery, measurement still within specs */ devc->lowbatt = 1; /* 0x20: PEAK */ /* 0x10: COUNT */ if (flags & 0x08) /* HOLD */ analog.mqflags |= SR_MQFLAG_HOLD; /* 0x04: LIMIT */ if (flags & 0x02) /* MAX */ analog.mqflags |= SR_MQFLAG_MAX; if (flags & 0x01) /* MIN */ analog.mqflags |= SR_MQFLAG_MIN; /* 16, 17 */ flags = (xgittoint(devc->buf[16]) << 8) | xgittoint(devc->buf[17]); /* 0xe0: undefined */ if (flags & 0x10) { /* LOBATT2: Low battery, measurement inaccurate */ devc->lowbatt = 2; sr_warn("Low battery, measurement quality degraded!"); } /* 0x08: SCALED */ /* 0x04: RATE (=lower resolution, allows higher rata rate up to 10/s. */ /* 0x02: Current clamp */ if (flags & 0x01) { /* dB */ /* * TODO: The Norma has an adjustable dB reference value. If * changed from default, this is not correct. */ if (analog.unit == SR_UNIT_VOLT) analog.unit = SR_UNIT_DECIBEL_VOLT; else analog.unit = SR_UNIT_UNITLESS; } /* 18, 19 */ /* flags = (xgittoint(devc->buf[18]) << 8) | xgittoint(devc->buf[19]); */ /* 0x80: Undefined. */ /* 0x40: Remote mode, keyboard locked */ /* 0x38: Undefined. */ /* 0x04: MIN > MAX */ /* 0x02: Measured value < Min */ /* 0x01: Measured value > Max */ /* 4: Flags. Evaluating this after setting value! */ flags = xgittoint(devc->buf[4]); if (flags & 0x04) /* Invalid value */ value = NAN; else if (flags & 0x01) /* Overload */ value = INFINITY; if (flags & 0x02) { /* Duplicate value, has been sent before. */ sr_spew("Duplicate value, dismissing!"); devc->buflen = 0; return; } sr_spew("range=%d/scale=%f/value=%f", range, (double)scale, (double)value); /* Finish and send packet. */ analog.channels = sdi->channels; analog.num_samples = 1; analog.data = &value; memset(&packet, 0, sizeof(packet)); packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(devc->cb_data, &packet); /* Finish processing. */ devc->num_samples++; devc->buflen = 0; } SR_PRIV int norma_dmm_receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_serial_dev_inst *serial; int len; gboolean terminating; gdouble elapsed_s; (void)fd; if (!(sdi = cb_data)) return TRUE; if (!(devc = sdi->priv)) return TRUE; serial = sdi->conn; if (revents == G_IO_IN) { /* Serial data arrived. */ while (NMADMM_BUFSIZE - devc->buflen - 1 > 0) { len = serial_read(serial, devc->buf + devc->buflen, 1); if (len < 1) break; devc->buflen += len; *(devc->buf + devc->buflen) = '\0'; if (*(devc->buf + devc->buflen - 1) == '\n') { /* * TODO: According to specs, should be \r, but * then we'd have to get rid of the \n. */ devc->last_req_pending = FALSE; nma_process_line(sdi); break; } } } /* If number of samples or time limit reached, stop acquisition. */ terminating = FALSE; if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) { sdi->driver->dev_acquisition_stop(sdi, cb_data); terminating = TRUE; } if (devc->limit_msec) { elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL); if ((elapsed_s * 1000) >= devc->limit_msec) { sdi->driver->dev_acquisition_stop(sdi, cb_data); terminating = TRUE; } } /* Request next package. */ if (!terminating && !devc->last_req_pending) { if (nma_send_req(sdi, NMADMM_REQ_STATUS, NULL) != SR_OK) return FALSE; } return TRUE; } libsigrok-0.3.0/hardware/norma-dmm/api.c0000644000175000017500000001634712332246667015047 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Matthias Heidbrink * * 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 . */ #include "protocol.h" static const int32_t hwopts[] = { SR_CONF_CONN, SR_CONF_SERIALCOMM, }; static const int32_t hwcaps[] = { SR_CONF_MULTIMETER, SR_CONF_LIMIT_SAMPLES, SR_CONF_LIMIT_MSEC, SR_CONF_CONTINUOUS, }; #define BUF_MAX 50 #define SERIALCOMM "4800/8n1/dtr=1/rts=0/flow=1" SR_PRIV struct sr_dev_driver norma_dmm_driver_info; static struct sr_dev_driver *di = &norma_dmm_driver_info; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct sr_dev_inst *sdi; struct drv_context *drvc; struct dev_context *devc; struct sr_config *src; struct sr_channel *ch; struct sr_serial_dev_inst *serial; GSList *l, *devices; int len, cnt; const char *conn, *serialcomm; char *buf; char fmttype[10]; char req[10]; int auxtype; devices = NULL; drvc = di->priv; drvc->instances = NULL; conn = serialcomm = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; case SR_CONF_SERIALCOMM: serialcomm = g_variant_get_string(src->data, NULL); break; } } if (!conn) return NULL; if (!serialcomm) serialcomm = SERIALCOMM; if (!(serial = sr_serial_dev_inst_new(conn, serialcomm))) return NULL; if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return NULL; serial_flush(serial); if (!(buf = g_try_malloc(BUF_MAX))) { sr_err("Serial buffer malloc failed."); return NULL; } snprintf(req, sizeof(req), "%s\r\n", nmadmm_requests[NMADMM_REQ_IDN].req_str); for (cnt = 0; cnt < 7; cnt++) { if (serial_write(serial, req, strlen(req)) == -1) { sr_err("Unable to send identification request: %d %s.", errno, strerror(errno)); return NULL; } len = BUF_MAX; serial_readline(serial, &buf, &len, 1500); if (!len) continue; buf[BUF_MAX - 1] = '\0'; /* Match ID string, e.g. "1834 065 V1.06,IF V1.02" (DM950) */ if (g_regex_match_simple("^1834 [^,]*,IF V*", (char *)buf, 0, 0)) { auxtype = xgittoint(buf[7]); // TODO: Will this work with non-DM950? snprintf(fmttype, sizeof(fmttype), "DM9%d0", auxtype); sr_spew("Norma %s DMM %s detected!", fmttype, &buf[9]); if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Norma", fmttype, buf + 9))) return NULL; if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } devc->type = auxtype; devc->version = g_strdup(&buf[9]); devc->elapsed_msec = g_timer_new(); sdi->conn = serial; sdi->priv = devc; sdi->driver = di; if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1"))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); break; } /* * The interface of the DM9x0 contains a cap that needs to * charge for up to 10s before the interface works, if not * powered externally. Therefore wait a little to improve * chances. */ if (cnt == 3) { sr_info("Waiting 5s to allow interface to settle."); g_usleep(5 * 1000 * 1000); } } g_free(buf); serial_close(serial); if (!devices) sr_serial_dev_inst_free(serial); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int dev_close(struct sr_dev_inst *sdi) { struct dev_context *devc; std_serial_dev_close(sdi); /* Free dynamically allocated resources. */ if ((devc = sdi->priv) && devc->version) { g_free(devc->version); devc->version = NULL; g_timer_destroy(devc->elapsed_msec); } return SR_OK; } static int cleanup(void) { return std_dev_clear(di, NULL); } static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return SR_ERR_BUG; } switch (key) { case SR_CONF_LIMIT_MSEC: /* TODO: not yet implemented */ if (g_variant_get_uint64(data) == 0) { sr_err("LIMIT_MSEC can't be 0."); return SR_ERR; } devc->limit_msec = g_variant_get_uint64(data); sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec); break; case SR_CONF_LIMIT_SAMPLES: devc->limit_samples = g_variant_get_uint64(data); sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples); break; default: return SR_ERR_NA; } return SR_OK; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; default: return SR_ERR_NA; } return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct sr_serial_dev_inst *serial; if (!sdi || !cb_data || !(devc = sdi->priv)) return SR_ERR_BUG; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc->cb_data = cb_data; /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* Start timer, if required. */ if (devc->limit_msec) g_timer_start(devc->elapsed_msec); /* Poll every 100ms, or whenever some data comes in. */ serial = sdi->conn; serial_source_add(serial, G_IO_IN, 100, norma_dmm_receive_data, (void *)sdi); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; /* Stop timer, if required. */ if (sdi && (devc = sdi->priv) && devc->limit_msec) g_timer_stop(devc->elapsed_msec); return std_serial_dev_acquisition_stop(sdi, cb_data, dev_close, sdi->conn, LOG_PREFIX); } SR_PRIV struct sr_dev_driver norma_dmm_driver_info = { .name = "norma-dmm", .longname = "Norma DM9x0 / Siemens B102x DMMs", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = NULL, .config_set = config_set, .config_list = config_list, .dev_open = std_serial_dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/uni-t-dmm/0000755000175000017500000000000012332246734014112 500000000000000libsigrok-0.3.0/hardware/uni-t-dmm/protocol.h0000644000175000017500000000614512332246667016057 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012-2013 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LIBSIGROK_HARDWARE_UNI_T_DMM_PROTOCOL_H #define LIBSIGROK_HARDWARE_UNI_T_DMM_PROTOCOL_H #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "uni-t-dmm" enum { TECPEL_DMM_8061, UNI_T_UT60A, UNI_T_UT60E, UNI_T_UT60G, UNI_T_UT61B, UNI_T_UT61C, UNI_T_UT61D, UNI_T_UT61E, VOLTCRAFT_VC820, VOLTCRAFT_VC830, VOLTCRAFT_VC840, TENMA_72_7745, TENMA_72_7750, }; struct dmm_info { char *vendor; char *device; uint32_t baudrate; int packet_size; gboolean (*packet_valid)(const uint8_t *); int (*packet_parse)(const uint8_t *, float *, struct sr_datafeed_analog *, void *); void (*dmm_details)(struct sr_datafeed_analog *, void *); struct sr_dev_driver *di; int (*receive_data)(int, int, void *); }; #define CHUNK_SIZE 8 #define DMM_BUFSIZE 256 /** Private, per-device-instance driver context. */ struct dev_context { /** The current sampling limit (in number of samples). */ uint64_t limit_samples; /** The current sampling limit (in ms). */ uint64_t limit_msec; /** Opaque pointer passed in by the frontend. */ void *cb_data; /** The current number of already received samples. */ uint64_t num_samples; int64_t starttime; gboolean first_run; uint8_t protocol_buf[DMM_BUFSIZE]; uint8_t bufoffset; uint8_t buflen; }; SR_PRIV int receive_data_TECPEL_DMM_8061(int fd, int revents, void *cb_data); SR_PRIV int receive_data_UNI_T_UT60A(int fd, int revents, void *cb_data); SR_PRIV int receive_data_UNI_T_UT60E(int fd, int revents, void *cb_data); SR_PRIV int receive_data_UNI_T_UT60G(int fd, int revents, void *cb_data); SR_PRIV int receive_data_UNI_T_UT61B(int fd, int revents, void *cb_data); SR_PRIV int receive_data_UNI_T_UT61C(int fd, int revents, void *cb_data); SR_PRIV int receive_data_UNI_T_UT61D(int fd, int revents, void *cb_data); SR_PRIV int receive_data_UNI_T_UT61E(int fd, int revents, void *cb_data); SR_PRIV int receive_data_VOLTCRAFT_VC820(int fd, int revents, void *cb_data); SR_PRIV int receive_data_VOLTCRAFT_VC830(int fd, int revents, void *cb_data); SR_PRIV int receive_data_VOLTCRAFT_VC840(int fd, int revents, void *cb_data); SR_PRIV int receive_data_TENMA_72_7745(int fd, int revents, void *cb_data); SR_PRIV int receive_data_TENMA_72_7750(int fd, int revents, void *cb_data); #endif libsigrok-0.3.0/hardware/uni-t-dmm/protocol.c0000644000175000017500000002300512332246667016044 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012-2013 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "protocol.h" extern struct dmm_info udmms[]; /* * Driver for various UNI-T multimeters (and rebranded ones). * * Most UNI-T DMMs can be used with two (three) different PC interface cables: * - The UT-D04 USB/HID cable, old version with Hoitek HE2325U chip. * - The UT-D04 USB/HID cable, new version with WCH CH9325 chip. * - The UT-D02 RS232 cable. * * This driver is meant to support all USB/HID cables, and various DMMs that * can be attached to a PC via these cables. Currently only the UT-D04 cable * (new version) is supported/tested. * The UT-D02 RS232 cable is handled by the 'serial-dmm' driver. * * The data for one DMM packet (e.g. 14 bytes if the respective DMM uses a * Fortune Semiconductor FS9922-DMM4 chip) is spread across multiple * 8-byte chunks. * * An 8-byte chunk looks like this: * - Byte 0: 0xfz, where z is the number of actual data bytes in this chunk. * - Bytes 1-7: z data bytes, the rest of the bytes should be ignored. * * Example: * f0 00 00 00 00 00 00 00 (no data bytes) * f2 55 77 00 00 00 00 00 (2 data bytes, 0x55 and 0x77) * f1 d1 00 00 00 00 00 00 (1 data byte, 0xd1) */ static void decode_packet(struct sr_dev_inst *sdi, int dmm, const uint8_t *buf, void *info) { struct dev_context *devc; struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; float floatval; int ret; devc = sdi->priv; memset(&analog, 0, sizeof(struct sr_datafeed_analog)); /* Parse the protocol packet. */ ret = udmms[dmm].packet_parse(buf, &floatval, &analog, info); if (ret != SR_OK) { sr_dbg("Invalid DMM packet, ignoring."); return; } /* If this DMM needs additional handling, call the resp. function. */ if (udmms[dmm].dmm_details) udmms[dmm].dmm_details(&analog, info); /* Send a sample packet with one analog value. */ analog.channels = sdi->channels; analog.num_samples = 1; analog.data = &floatval; packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(devc->cb_data, &packet); /* Increase sample count. */ devc->num_samples++; } static int hid_chip_init(struct sr_dev_inst *sdi, uint16_t baudrate) { int ret; uint8_t buf[5]; struct sr_usb_dev_inst *usb; usb = sdi->conn; /* Detach kernel drivers which grabbed this device (if any). */ if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) { ret = libusb_detach_kernel_driver(usb->devhdl, 0); if (ret < 0) { sr_err("Failed to detach kernel driver: %s.", libusb_error_name(ret)); return SR_ERR; } sr_dbg("Successfully detached kernel driver."); } else { sr_dbg("No need to detach a kernel driver."); } /* Claim interface 0. */ if ((ret = libusb_claim_interface(usb->devhdl, 0)) < 0) { sr_err("Failed to claim interface 0: %s.", libusb_error_name(ret)); return SR_ERR; } sr_dbg("Successfully claimed interface 0."); /* Set data for the HID feature report (e.g. baudrate). */ buf[0] = baudrate & 0xff; /* Baudrate, LSB */ buf[1] = (baudrate >> 8) & 0xff; /* Baudrate, MSB */ buf[2] = 0x00; /* Unknown/unused (?) */ buf[3] = 0x00; /* Unknown/unused (?) */ buf[4] = 0x03; /* Unknown, always 0x03. */ /* Send HID feature report to setup the baudrate/chip. */ sr_dbg("Sending initial HID feature report."); sr_spew("HID init = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x (%d baud)", buf[0], buf[1], buf[2], buf[3], buf[4], baudrate); ret = libusb_control_transfer( usb->devhdl, /* libusb device handle */ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, 9, /* bRequest: HID set_report */ 0x300, /* wValue: HID feature, report number 0 */ 0, /* wIndex: interface 0 */ (unsigned char *)&buf, /* payload buffer */ 5, /* wLength: 5 bytes payload */ 1000 /* timeout (ms) */); if (ret < 0) { sr_err("HID feature report error: %s.", libusb_error_name(ret)); return SR_ERR; } if (ret != 5) { /* TODO: Handle better by also sending the remaining bytes. */ sr_err("Short packet: sent %d/5 bytes.", ret); return SR_ERR; } sr_dbg("Successfully sent initial HID feature report."); return SR_OK; } static void log_8byte_chunk(const uint8_t *buf) { sr_spew("8-byte chunk: %02x %02x %02x %02x %02x %02x %02x %02x " "(%d data bytes)", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], (buf[0] & 0x0f)); } static void log_dmm_packet(const uint8_t *buf) { sr_dbg("DMM packet: %02x %02x %02x %02x %02x %02x %02x" " %02x %02x %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]); } static int get_and_handle_data(struct sr_dev_inst *sdi, int dmm, void *info) { struct dev_context *devc; uint8_t buf[CHUNK_SIZE], *pbuf; int i, ret, len, num_databytes_in_chunk; struct sr_usb_dev_inst *usb; devc = sdi->priv; usb = sdi->conn; pbuf = devc->protocol_buf; /* On the first run, we need to init the HID chip. */ if (devc->first_run) { if ((ret = hid_chip_init(sdi, udmms[dmm].baudrate)) != SR_OK) { sr_err("HID chip init failed: %d.", ret); return SR_ERR; } memset(pbuf, 0x00, DMM_BUFSIZE); devc->first_run = FALSE; } memset(&buf, 0x00, CHUNK_SIZE); /* Get data from EP2 using an interrupt transfer. */ ret = libusb_interrupt_transfer( usb->devhdl, /* libusb device handle */ LIBUSB_ENDPOINT_IN | 2, /* EP2, IN */ (unsigned char *)&buf, /* receive buffer */ CHUNK_SIZE, /* wLength */ &len, /* actually received byte count */ 1000 /* timeout (ms) */); if (ret < 0) { sr_err("USB receive error: %s.", libusb_error_name(ret)); return SR_ERR; } if (len != CHUNK_SIZE) { sr_err("Short packet: received %d/%d bytes.", len, CHUNK_SIZE); /* TODO: Print the bytes? */ return SR_ERR; } log_8byte_chunk((const uint8_t *)&buf); /* If there are no data bytes just return (without error). */ if (buf[0] == 0xf0) return SR_OK; devc->bufoffset = 0; /* * Append the 1-7 data bytes of this chunk to pbuf. * * Special case: * DMMs with Cyrustek ES51922 chip need serial settings of * 19230/7o1. The WCH CH9325 UART to USB/HID chip used in (some * versions of) the UNI-T UT-D04 cable however, will also send * the parity bit to the host in the 8-byte data chunks. This bit * is encoded in bit 7 of each of the 1-7 data bytes and must thus * be removed in order for the actual ES51922 protocol parser to * work properly. */ num_databytes_in_chunk = buf[0] & 0x0f; for (i = 0; i < num_databytes_in_chunk; i++, devc->buflen++) { pbuf[devc->buflen] = buf[1 + i]; if (udmms[dmm].packet_parse == sr_es519xx_19200_14b_parse) pbuf[devc->buflen] &= ~(1 << 7); } /* Now look for packets in that data. */ while ((devc->buflen - devc->bufoffset) >= udmms[dmm].packet_size) { if (udmms[dmm].packet_valid(pbuf + devc->bufoffset)) { log_dmm_packet(pbuf + devc->bufoffset); decode_packet(sdi, dmm, pbuf + devc->bufoffset, info); devc->bufoffset += udmms[dmm].packet_size; } else { devc->bufoffset++; } } /* Move remaining bytes to beginning of buffer. */ for (i = 0; i < devc->buflen - devc->bufoffset; i++) pbuf[i] = pbuf[devc->bufoffset + i]; devc->buflen -= devc->bufoffset; return SR_OK; } static int receive_data(int fd, int revents, int dmm, void *info, void *cb_data) { int ret; struct sr_dev_inst *sdi; struct dev_context *devc; int64_t time_ms; (void)fd; (void)revents; sdi = cb_data; devc = sdi->priv; if ((ret = get_and_handle_data(sdi, dmm, info)) != SR_OK) return FALSE; /* Abort acquisition if we acquired enough samples. */ if (devc->limit_samples && devc->num_samples >= devc->limit_samples) { sr_info("Requested number of samples reached."); sdi->driver->dev_acquisition_stop(sdi, cb_data); } if (devc->limit_msec) { time_ms = (g_get_monotonic_time() - devc->starttime) / 1000; if (time_ms > (int64_t)devc->limit_msec) { sr_info("Requested time limit reached."); sdi->driver->dev_acquisition_stop(sdi, cb_data); return TRUE; } } return TRUE; } #define RECEIVE_DATA(ID_UPPER, DMM_DRIVER) \ SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \ struct DMM_DRIVER##_info info; \ return receive_data(fd, revents, ID_UPPER, &info, cb_data); } /* Driver-specific receive_data() wrappers */ RECEIVE_DATA(TECPEL_DMM_8061, fs9721) RECEIVE_DATA(UNI_T_UT60A, fs9721) RECEIVE_DATA(UNI_T_UT60E, fs9721) RECEIVE_DATA(UNI_T_UT60G, es519xx) RECEIVE_DATA(UNI_T_UT61B, fs9922) RECEIVE_DATA(UNI_T_UT61C, fs9922) RECEIVE_DATA(UNI_T_UT61D, fs9922) RECEIVE_DATA(UNI_T_UT61E, es519xx) RECEIVE_DATA(VOLTCRAFT_VC820, fs9721) RECEIVE_DATA(VOLTCRAFT_VC830, fs9922) RECEIVE_DATA(VOLTCRAFT_VC840, fs9721) RECEIVE_DATA(TENMA_72_7745, es519xx) RECEIVE_DATA(TENMA_72_7750, es519xx) libsigrok-0.3.0/hardware/uni-t-dmm/api.c0000644000175000017500000002662512332246667014767 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012-2013 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "protocol.h" #define UNI_T_UT_D04_NEW "1a86.e008" static const int32_t hwopts[] = { SR_CONF_CONN, }; static const int32_t hwcaps[] = { SR_CONF_MULTIMETER, SR_CONF_LIMIT_SAMPLES, SR_CONF_LIMIT_MSEC, SR_CONF_CONTINUOUS, }; SR_PRIV struct sr_dev_driver tecpel_dmm_8061_driver_info; SR_PRIV struct sr_dev_driver uni_t_ut60a_driver_info; SR_PRIV struct sr_dev_driver uni_t_ut60e_driver_info; SR_PRIV struct sr_dev_driver uni_t_ut60g_driver_info; SR_PRIV struct sr_dev_driver uni_t_ut61b_driver_info; SR_PRIV struct sr_dev_driver uni_t_ut61c_driver_info; SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info; SR_PRIV struct sr_dev_driver uni_t_ut61e_driver_info; SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info; SR_PRIV struct sr_dev_driver voltcraft_vc830_driver_info; SR_PRIV struct sr_dev_driver voltcraft_vc840_driver_info; SR_PRIV struct sr_dev_driver tenma_72_7745_driver_info; SR_PRIV struct sr_dev_driver tenma_72_7750_driver_info; SR_PRIV struct dmm_info udmms[] = { { "Tecpel", "DMM-8061", 2400, FS9721_PACKET_SIZE, sr_fs9721_packet_valid, sr_fs9721_parse, sr_fs9721_00_temp_c, &tecpel_dmm_8061_driver_info, receive_data_TECPEL_DMM_8061, }, { "UNI-T", "UT60A", 2400, FS9721_PACKET_SIZE, sr_fs9721_packet_valid, sr_fs9721_parse, NULL, &uni_t_ut60a_driver_info, receive_data_UNI_T_UT60A, }, { "UNI-T", "UT60E", 2400, FS9721_PACKET_SIZE, sr_fs9721_packet_valid, sr_fs9721_parse, sr_fs9721_00_temp_c, &uni_t_ut60e_driver_info, receive_data_UNI_T_UT60E, }, { /* The baudrate is actually 19230, see "Note 1" below. */ "UNI-T", "UT60G", 19200, ES519XX_11B_PACKET_SIZE, sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse, NULL, &uni_t_ut60g_driver_info, receive_data_UNI_T_UT60G, }, { "UNI-T", "UT61B", 2400, FS9922_PACKET_SIZE, sr_fs9922_packet_valid, sr_fs9922_parse, NULL, &uni_t_ut61b_driver_info, receive_data_UNI_T_UT61B, }, { "UNI-T", "UT61C", 2400, FS9922_PACKET_SIZE, sr_fs9922_packet_valid, sr_fs9922_parse, NULL, &uni_t_ut61c_driver_info, receive_data_UNI_T_UT61C, }, { "UNI-T", "UT61D", 2400, FS9922_PACKET_SIZE, sr_fs9922_packet_valid, sr_fs9922_parse, NULL, &uni_t_ut61d_driver_info, receive_data_UNI_T_UT61D, }, { /* The baudrate is actually 19230, see "Note 1" below. */ "UNI-T", "UT61E", 19200, ES519XX_14B_PACKET_SIZE, sr_es519xx_19200_14b_packet_valid, sr_es519xx_19200_14b_parse, NULL, &uni_t_ut61e_driver_info, receive_data_UNI_T_UT61E, }, { "Voltcraft", "VC-820", 2400, FS9721_PACKET_SIZE, sr_fs9721_packet_valid, sr_fs9721_parse, NULL, &voltcraft_vc820_driver_info, receive_data_VOLTCRAFT_VC820, }, { /* * Note: The VC830 doesn't set the 'volt' and 'diode' bits of * the FS9922 protocol. Instead, it only sets the user-defined * bit "z1" to indicate "diode mode" and "voltage". */ "Voltcraft", "VC-830", 2400, FS9922_PACKET_SIZE, sr_fs9922_packet_valid, sr_fs9922_parse, &sr_fs9922_z1_diode, &voltcraft_vc830_driver_info, receive_data_VOLTCRAFT_VC830, }, { "Voltcraft", "VC-840", 2400, FS9721_PACKET_SIZE, sr_fs9721_packet_valid, sr_fs9721_parse, sr_fs9721_00_temp_c, &voltcraft_vc840_driver_info, receive_data_VOLTCRAFT_VC840, }, { "Tenma", "72-7745", 2400, FS9721_PACKET_SIZE, sr_fs9721_packet_valid, sr_fs9721_parse, sr_fs9721_00_temp_c, &tenma_72_7745_driver_info, receive_data_TENMA_72_7745, }, { /* The baudrate is actually 19230, see "Note 1" below. */ "Tenma", "72-7750", 19200, ES519XX_11B_PACKET_SIZE, sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse, NULL, &tenma_72_7750_driver_info, receive_data_TENMA_72_7750, }, }; /* * Note 1: The actual baudrate of the Cyrustek ES519xx chip used in this DMM * is 19230. However, the WCH CH9325 chip (UART to USB/HID) used in (some * versions of) the UNI-T UT-D04 cable doesn't support 19230 baud. It only * supports 19200, and setting an unsupported baudrate will result in the * default of 2400 being used (which will not work with this DMM, of course). */ static int dev_clear(int dmm) { return std_dev_clear(udmms[dmm].di, NULL); } static int init(struct sr_context *sr_ctx, int dmm) { sr_dbg("Selected '%s' subdriver.", udmms[dmm].di->name); return std_init(sr_ctx, udmms[dmm].di, LOG_PREFIX); } static GSList *scan(GSList *options, int dmm) { GSList *usb_devices, *devices, *l; struct sr_dev_inst *sdi; struct dev_context *devc; struct drv_context *drvc; struct sr_usb_dev_inst *usb; struct sr_config *src; struct sr_channel *ch; const char *conn; drvc = udmms[dmm].di->priv; conn = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; } } if (!conn) return NULL; devices = NULL; if (!(usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) { g_slist_free_full(usb_devices, g_free); return NULL; } for (l = usb_devices; l; l = l->next) { usb = l->data; if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } devc->first_run = TRUE; if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, udmms[dmm].vendor, udmms[dmm].device, NULL))) { sr_err("sr_dev_inst_new returned NULL."); return NULL; } sdi->priv = devc; sdi->driver = udmms[dmm].di; if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1"))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); sdi->inst_type = SR_INST_USB; sdi->conn = usb; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); } return devices; } static GSList *dev_list(int dmm) { return ((struct drv_context *)(udmms[dmm].di->priv))->instances; } static int dev_open(struct sr_dev_inst *sdi, int dmm) { struct drv_context *drvc; struct sr_usb_dev_inst *usb; int ret; drvc = udmms[dmm].di->priv; usb = sdi->conn; if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) == SR_OK) sdi->status = SR_ST_ACTIVE; return ret; } static int dev_close(struct sr_dev_inst *sdi) { /* TODO */ sdi->status = SR_ST_INACTIVE; return SR_OK; } static int cleanup(int dmm) { return dev_clear(dmm); } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; devc = sdi->priv; switch (id) { case SR_CONF_LIMIT_MSEC: if (g_variant_get_uint64(data) == 0) { sr_err("Time limit cannot be 0."); return SR_ERR; } devc->limit_msec = g_variant_get_uint64(data); sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec); break; case SR_CONF_LIMIT_SAMPLES: if (g_variant_get_uint64(data) == 0) { sr_err("Sample limit cannot be 0."); return SR_ERR; } devc->limit_samples = g_variant_get_uint64(data); sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples); break; default: return SR_ERR_NA; } return SR_OK; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; default: return SR_ERR_NA; } return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data, int dmm) { struct dev_context *devc; devc = sdi->priv; devc->cb_data = cb_data; devc->starttime = g_get_monotonic_time(); /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); sr_source_add(0, 0, 10 /* poll_timeout */, udmms[dmm].receive_data, (void *)sdi); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { struct sr_datafeed_packet packet; (void)sdi; sr_dbg("Stopping acquisition."); /* Send end packet to the session bus. */ sr_dbg("Sending SR_DF_END."); packet.type = SR_DF_END; sr_session_send(cb_data, &packet); /* TODO? */ sr_source_remove(0); return SR_OK; } /* Driver-specific API function wrappers */ #define HW_INIT(X) \ static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); } #define HW_CLEANUP(X) \ static int cleanup_##X(void) { return cleanup(X); } #define HW_SCAN(X) \ static GSList *scan_##X(GSList *options) { return scan(options, X); } #define HW_DEV_LIST(X) \ static GSList *dev_list_##X(void) { return dev_list(X); } #define HW_DEV_CLEAR(X) \ static int dev_clear_##X(void) { return dev_clear(X); } #define HW_DEV_ACQUISITION_START(X) \ static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \ void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); } #define HW_DEV_OPEN(X) \ static int dev_open_##X(struct sr_dev_inst *sdi) { return dev_open(sdi, X); } /* Driver structs and API function wrappers */ #define DRV(ID, ID_UPPER, NAME, LONGNAME) \ HW_INIT(ID_UPPER) \ HW_CLEANUP(ID_UPPER) \ HW_SCAN(ID_UPPER) \ HW_DEV_LIST(ID_UPPER) \ HW_DEV_CLEAR(ID_UPPER) \ HW_DEV_ACQUISITION_START(ID_UPPER) \ HW_DEV_OPEN(ID_UPPER) \ SR_PRIV struct sr_dev_driver ID##_driver_info = { \ .name = NAME, \ .longname = LONGNAME, \ .api_version = 1, \ .init = init_##ID_UPPER, \ .cleanup = cleanup_##ID_UPPER, \ .scan = scan_##ID_UPPER, \ .dev_list = dev_list_##ID_UPPER, \ .dev_clear = dev_clear_##ID_UPPER, \ .config_get = NULL, \ .config_set = config_set, \ .config_list = config_list, \ .dev_open = dev_open_##ID_UPPER, \ .dev_close = dev_close, \ .dev_acquisition_start = dev_acquisition_start_##ID_UPPER, \ .dev_acquisition_stop = dev_acquisition_stop, \ .priv = NULL, \ }; DRV(tecpel_dmm_8061, TECPEL_DMM_8061, "tecpel-dmm-8061", "Tecpel DMM-8061") DRV(uni_t_ut60a, UNI_T_UT60A, "uni-t-ut60a", "UNI-T UT60A") DRV(uni_t_ut60e, UNI_T_UT60E, "uni-t-ut60e", "UNI-T UT60E") DRV(uni_t_ut60g, UNI_T_UT60G, "uni-t-ut60g", "UNI-T UT60G") DRV(uni_t_ut61b, UNI_T_UT61B, "uni-t-ut61b", "UNI-T UT61B") DRV(uni_t_ut61c, UNI_T_UT61C, "uni-t-ut61c", "UNI-T UT61C") DRV(uni_t_ut61d, UNI_T_UT61D, "uni-t-ut61d", "UNI-T UT61D") DRV(uni_t_ut61e, UNI_T_UT61E, "uni-t-ut61e", "UNI-T UT61E") DRV(voltcraft_vc820, VOLTCRAFT_VC820, "voltcraft-vc820", "Voltcraft VC-820") DRV(voltcraft_vc830, VOLTCRAFT_VC830, "voltcraft-vc830", "Voltcraft VC-830") DRV(voltcraft_vc840, VOLTCRAFT_VC840, "voltcraft-vc840", "Voltcraft VC-840") DRV(tenma_72_7745, TENMA_72_7745, "tenma-72-7745", "Tenma 72-7745") DRV(tenma_72_7750, TENMA_72_7750, "tenma-72-7750", "Tenma 72-7750") libsigrok-0.3.0/hardware/chronovu-la/0000755000175000017500000000000012332246734014540 500000000000000libsigrok-0.3.0/hardware/chronovu-la/protocol.h0000644000175000017500000000775312332246667016513 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2011-2014 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LIBSIGROK_HARDWARE_CHRONOVU_LA_PROTOCOL_H #define LIBSIGROK_HARDWARE_CHRONOVU_LA_PROTOCOL_H #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "la8/la16" #define SDRAM_SIZE (8 * 1024 * 1024) #define MAX_NUM_SAMPLES SDRAM_SIZE #define BS 4096 /* Block size */ #define NUM_BLOCKS 2048 /* Number of blocks */ enum { CHRONOVU_LA8, CHRONOVU_LA16, }; struct cv_profile { int model; const char *modelname; const char *iproduct; /* USB iProduct string */ unsigned int num_channels; uint64_t max_samplerate; const char *trigger_type; float trigger_constant; }; /* Private, per-device-instance driver context. */ struct dev_context { /** Device profile struct for this device. */ const struct cv_profile *prof; /** FTDI device context (used by libftdi). */ struct ftdi_context *ftdic; /** The currently configured samplerate of the device. */ uint64_t cur_samplerate; /** The current sampling limit (in ms). */ uint64_t limit_msec; /** The current sampling limit (in number of samples). */ uint64_t limit_samples; void *cb_data; /** * A buffer containing some (mangled) samples from the device. * Format: Pretty mangled-up (due to hardware reasons), see code. */ uint8_t mangled_buf[BS]; /** * An 8MB buffer where we'll store the de-mangled samples. * LA8: Each sample is 1 byte, MSB is channel 7, LSB is channel 0. * LA16: Each sample is 2 bytes, MSB is channel 15, LSB is channel 0. */ uint8_t *final_buf; /** * Trigger pattern. * A 1 bit matches a high signal, 0 matches a low signal on a channel. * * If the resp. 'trigger_edgemask' bit is set, 1 means "rising edge", * and 0 means "falling edge". */ uint16_t trigger_pattern; /** * Trigger mask. * A 1 bit means "must match trigger_pattern", 0 means "don't care". */ uint16_t trigger_mask; /** * Trigger edge mask. * A 1 bit means "edge triggered", 0 means "state triggered". * * Edge triggering is only supported on LA16 (but not LA8). */ uint16_t trigger_edgemask; /** Tells us whether an SR_DF_TRIGGER packet was already sent. */ int trigger_found; /** Used for keeping track how much time has passed. */ gint64 done; /** Counter/index for the data block to be read. */ int block_counter; /** The divcount value (determines the sample period). */ uint8_t divcount; /** This ChronoVu device's USB VID/PID. */ uint16_t usb_vid; uint16_t usb_pid; /** Samplerates supported by this device. */ uint64_t samplerates[255]; }; /* protocol.c */ extern SR_PRIV const char *cv_channel_names[]; extern const struct cv_profile cv_profiles[]; SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi); SR_PRIV uint8_t cv_samplerate_to_divcount(const struct sr_dev_inst *sdi, uint64_t samplerate); SR_PRIV int cv_write(struct dev_context *devc, uint8_t *buf, int size); SR_PRIV int cv_configure_channels(const struct sr_dev_inst *sdi); SR_PRIV int cv_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate); SR_PRIV int cv_read_block(struct dev_context *devc); SR_PRIV void cv_send_block_to_session_bus(struct dev_context *devc, int block); #endif libsigrok-0.3.0/hardware/chronovu-la/protocol.c0000644000175000017500000003625012332246667016500 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2011-2014 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "protocol.h" SR_PRIV const struct cv_profile cv_profiles[] = { { CHRONOVU_LA8, "LA8", "ChronoVu LA8", 8, SR_MHZ(100), "01", 0.8388608 }, { CHRONOVU_LA16, "LA16", "ChronoVu LA16", 16, SR_MHZ(200), "01rf", 0.042 }, { 0, NULL, NULL, 0, 0, NULL, 0.0 }, }; /* LA8: channels are numbered 0-7. LA16: channels are numbered 0-15. */ SR_PRIV const char *cv_channel_names[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", }; static int close_usb_reset_sequencer(struct dev_context *devc); SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi) { int i; struct dev_context *devc; devc = sdi->priv; if (devc->samplerates[0] != 0) return; for (i = 0; i < 255; i++) devc->samplerates[254 - i] = devc->prof->max_samplerate / (i + 1); } /** * Check if the given samplerate is supported by the hardware. * * @param sdi Device instance. * @param samplerate The samplerate (in Hz) to check. * * @return 1 if the samplerate is supported/valid, 0 otherwise. */ static int is_valid_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate) { int i; struct dev_context *devc; devc = sdi->priv; cv_fill_samplerates_if_needed(sdi); for (i = 0; i < 255; i++) { if (devc->samplerates[i] == samplerate) return 1; } sr_err("Invalid samplerate (%" PRIu64 "Hz).", samplerate); return 0; } /** * Convert a samplerate (in Hz) to the 'divcount' value the device wants. * * The divcount value can be 0x00 - 0xfe (0xff is not valid). * * LA8: * sample period = (divcount + 1) * 10ns. * divcount = 0x00: 10ns period, 100MHz samplerate. * divcount = 0xfe: 2550ns period, 392.15kHz samplerate. * * LA16: * sample period = (divcount + 1) * 5ns. * divcount = 0x00: 5ns period, 200MHz samplerate. * divcount = 0xfe: 1275ns period, ~784.31kHz samplerate. * * @param sdi Device instance. * @param samplerate The samplerate in Hz. * * @return The divcount value as needed by the hardware, or 0xff upon errors. */ SR_PRIV uint8_t cv_samplerate_to_divcount(const struct sr_dev_inst *sdi, uint64_t samplerate) { struct dev_context *devc; devc = sdi->priv; if (samplerate == 0) { sr_err("Can't convert invalid samplerate of 0 Hz."); return 0xff; } if (!is_valid_samplerate(sdi, samplerate)) { sr_err("Can't get divcount, samplerate invalid."); return 0xff; } return (devc->prof->max_samplerate / samplerate) - 1; } /** * Write data of a certain length to the FTDI device. * * @param devc The struct containing private per-device-instance data. Must not * be NULL. devc->ftdic must not be NULL either. * @param buf The buffer containing the data to write. Must not be NULL. * @param size The number of bytes to write. Must be > 0. * * @return The number of bytes written, or a negative value upon errors. */ SR_PRIV int cv_write(struct dev_context *devc, uint8_t *buf, int size) { int bytes_written; /* Note: Caller ensures devc/devc->ftdic/buf != NULL and size > 0. */ bytes_written = ftdi_write_data(devc->ftdic, buf, size); if (bytes_written < 0) { sr_err("Failed to write data (%d): %s.", bytes_written, ftdi_get_error_string(devc->ftdic)); (void) close_usb_reset_sequencer(devc); /* Ignore errors. */ } else if (bytes_written != size) { sr_err("Failed to write data, only %d/%d bytes written.", size, bytes_written); (void) close_usb_reset_sequencer(devc); /* Ignore errors. */ } return bytes_written; } /** * Read a certain amount of bytes from the FTDI device. * * @param devc The struct containing private per-device-instance data. Must not * be NULL. devc->ftdic must not be NULL either. * @param buf The buffer where the received data will be stored. Must not * be NULL. * @param size The number of bytes to read. Must be >= 1. * * @return The number of bytes read, or a negative value upon errors. */ static int cv_read(struct dev_context *devc, uint8_t *buf, int size) { int bytes_read; /* Note: Caller ensures devc/devc->ftdic/buf != NULL and size > 0. */ bytes_read = ftdi_read_data(devc->ftdic, buf, size); if (bytes_read < 0) { sr_err("Failed to read data (%d): %s.", bytes_read, ftdi_get_error_string(devc->ftdic)); } else if (bytes_read != size) { // sr_err("Failed to read data, only %d/%d bytes read.", // bytes_read, size); } return bytes_read; } /** * Close the USB port and reset the sequencer logic. * * @param devc The struct containing private per-device-instance data. * * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments. */ static int close_usb_reset_sequencer(struct dev_context *devc) { /* Magic sequence of bytes for resetting the sequencer logic. */ uint8_t buf[8] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; int ret; /* Note: Caller checked that devc and devc->ftdic != NULL. */ if (devc->ftdic->usb_dev) { /* Reset the sequencer logic, then wait 100ms. */ sr_dbg("Resetting sequencer logic."); (void) cv_write(devc, buf, 8); /* Ignore errors. */ g_usleep(100 * 1000); /* Purge FTDI buffers, then reset and close the FTDI device. */ sr_dbg("Purging buffers, resetting+closing FTDI device."); /* Log errors, but ignore them (i.e., don't abort). */ if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) sr_err("Failed to purge FTDI buffers (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); if ((ret = ftdi_usb_reset(devc->ftdic)) < 0) sr_err("Failed to reset FTDI device (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); if ((ret = ftdi_usb_close(devc->ftdic)) < 0) sr_err("Failed to close FTDI device (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); } /* Close USB device, deinitialize and free the FTDI context. */ ftdi_free(devc->ftdic); devc->ftdic = NULL; return SR_OK; } /** * Reset the ChronoVu device. * * A reset is required after a failed read/write operation or upon timeouts. * * @param devc The struct containing private per-device-instance data. * * @return SR_OK upon success, SR_ERR upon failure. */ static int reset_device(struct dev_context *devc) { uint8_t buf[BS]; gint64 done, now; int bytes_read; /* Note: Caller checked that devc and devc->ftdic != NULL. */ sr_dbg("Resetting the device."); /* * Purge pending read data from the FTDI hardware FIFO until * no more data is left, or a timeout occurs (after 20s). */ done = (20 * G_TIME_SPAN_SECOND) + g_get_monotonic_time(); do { /* Try to read bytes until none are left (or errors occur). */ bytes_read = cv_read(devc, (uint8_t *)&buf, BS); now = g_get_monotonic_time(); } while ((done > now) && (bytes_read > 0)); /* Reset the sequencer logic and close the USB port. */ (void) close_usb_reset_sequencer(devc); /* Ignore errors. */ sr_dbg("Device reset finished."); return SR_OK; } SR_PRIV int cv_configure_channels(const struct sr_dev_inst *sdi) { struct dev_context *devc; const struct sr_channel *ch; const GSList *l; uint16_t channel_bit; char *tc; devc = sdi->priv; devc->trigger_pattern = 0x0000; /* Default to "low" trigger. */ devc->trigger_mask = 0x0000; /* Default to "don't care". */ devc->trigger_edgemask = 0x0000; /* Default to "state triggered". */ for (l = sdi->channels; l; l = l->next) { ch = (struct sr_channel *)l->data; if (!ch) { sr_err("%s: channel was NULL.", __func__); return SR_ERR; } /* Skip disabled channels. */ if (!ch->enabled) continue; /* Skip (enabled) channels with no configured trigger. */ if (!ch->trigger) continue; /* Note: Must only be run if ch->trigger != NULL. */ if (ch->index < 0 || ch->index > (int)devc->prof->num_channels - 1) { sr_err("Invalid channel index %d, must be " "between 0 and %d.", ch->index, devc->prof->num_channels - 1); return SR_ERR; } channel_bit = (1 << (ch->index)); /* Configure the channel's trigger pattern/mask/edgemask. */ for (tc = ch->trigger; tc && *tc; tc++) { devc->trigger_mask |= channel_bit; /* Sanity check, LA8 only supports low/high trigger. */ if ((devc->prof->model == CHRONOVU_LA8) && (*tc != '0' && *tc != '1')) { sr_err("Invalid trigger '%c', only " "'0'/'1' supported.", *tc); return SR_ERR; } /* state: 1 == high, edge: 1 == rising edge. */ if (*tc == '1' || *tc == 'r') devc->trigger_pattern |= channel_bit; /* LA16 (but not LA8) supports edge triggering. */ if ((devc->prof->model == CHRONOVU_LA16)) { if (*tc == 'r' || *tc == 'f') devc->trigger_edgemask |= channel_bit; } } } sr_dbg("Trigger pattern/mask/edgemask = 0x%04x / 0x%04x / 0x%04x.", devc->trigger_pattern, devc->trigger_mask, devc->trigger_edgemask); return SR_OK; } SR_PRIV int cv_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate) { struct dev_context *devc; /* Note: Caller checked that sdi and sdi->priv != NULL. */ devc = sdi->priv; sr_spew("Trying to set samplerate to %" PRIu64 "Hz.", samplerate); cv_fill_samplerates_if_needed(sdi); /* Check if this is a samplerate supported by the hardware. */ if (!is_valid_samplerate(sdi, samplerate)) { sr_dbg("Failed to set invalid samplerate (%" PRIu64 "Hz).", samplerate); return SR_ERR; } devc->cur_samplerate = samplerate; sr_dbg("Samplerate set to %" PRIu64 "Hz.", devc->cur_samplerate); return SR_OK; } /** * Get a block of data from the device. * * @param devc The struct containing private per-device-instance data. Must not * be NULL. devc->ftdic must not be NULL either. * * @return SR_OK upon success, or SR_ERR upon errors. */ SR_PRIV int cv_read_block(struct dev_context *devc) { int i, byte_offset, m, mi, p, q, index, bytes_read; gint64 now; /* Note: Caller checked that devc and devc->ftdic != NULL. */ sr_spew("Reading block %d.", devc->block_counter); bytes_read = cv_read(devc, devc->mangled_buf, BS); /* If first block read got 0 bytes, retry until success or timeout. */ if ((bytes_read == 0) && (devc->block_counter == 0)) { do { sr_spew("Reading block 0 (again)."); /* Note: If bytes_read < 0 cv_read() will log errors. */ bytes_read = cv_read(devc, devc->mangled_buf, BS); now = g_get_monotonic_time(); } while ((devc->done > now) && (bytes_read == 0)); } /* Check if block read was successful or a timeout occured. */ if (bytes_read != BS) { sr_err("Trigger timed out. Bytes read: %d.", bytes_read); (void) reset_device(devc); /* Ignore errors. */ return SR_ERR; } /* De-mangle the data. */ sr_spew("Demangling block %d.", devc->block_counter); byte_offset = devc->block_counter * BS; m = byte_offset / (1024 * 1024); mi = m * (1024 * 1024); for (i = 0; i < BS; i++) { if (devc->prof->model == CHRONOVU_LA8) { p = i & (1 << 0); index = m * 2 + (((byte_offset + i) - mi) / 2) * 16; index += (devc->divcount == 0) ? p : (1 - p); } else { p = i & (1 << 0); q = i & (1 << 1); index = m * 4 + (((byte_offset + i) - mi) / 4) * 32; index += q + (1 - p); } devc->final_buf[index] = devc->mangled_buf[i]; } return SR_OK; } SR_PRIV void cv_send_block_to_session_bus(struct dev_context *devc, int block) { int i, idx; uint8_t sample, expected_sample, tmp8; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; int trigger_point; /* Relative trigger point (in this block). */ /* Note: Caller ensures devc/devc->ftdic != NULL and block > 0. */ /* TODO: Implement/test proper trigger support for the LA16. */ /* Check if we can find the trigger condition in this block. */ trigger_point = -1; expected_sample = devc->trigger_pattern & devc->trigger_mask; for (i = 0; i < BS; i++) { /* Don't continue if the trigger was found previously. */ if (devc->trigger_found) break; /* * Also, don't continue if triggers are "don't care", i.e. if * no trigger conditions were specified by the user. In that * case we don't want to send an SR_DF_TRIGGER packet at all. */ if (devc->trigger_mask == 0x0000) break; sample = *(devc->final_buf + (block * BS) + i); if ((sample & devc->trigger_mask) == expected_sample) { trigger_point = i; devc->trigger_found = 1; break; } } /* Swap low and high bytes of the 16-bit LA16 samples. */ if (devc->prof->model == CHRONOVU_LA16) { for (i = 0; i < BS; i += 2) { idx = (block * BS) + i; tmp8 = devc->final_buf[idx]; devc->final_buf[idx] = devc->final_buf[idx + 1]; devc->final_buf[idx + 1] = tmp8; } } /* If no trigger was found, send one SR_DF_LOGIC packet. */ if (trigger_point == -1) { /* Send an SR_DF_LOGIC packet to the session bus. */ sr_spew("Sending SR_DF_LOGIC packet (%d bytes) for " "block %d.", BS, block); packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = BS; logic.unitsize = devc->prof->num_channels / 8; logic.data = devc->final_buf + (block * BS); sr_session_send(devc->cb_data, &packet); return; } /* * We found the trigger, so some special handling is needed. We have * to send an SR_DF_LOGIC packet with the samples before the trigger * (if any), then the SD_DF_TRIGGER packet itself, then another * SR_DF_LOGIC packet with the samples after the trigger (if any). */ /* TODO: Send SR_DF_TRIGGER packet before or after the actual sample? */ /* If at least one sample is located before the trigger... */ if (trigger_point > 0) { /* Send pre-trigger SR_DF_LOGIC packet to the session bus. */ sr_spew("Sending pre-trigger SR_DF_LOGIC packet, " "start = %d, length = %d.", block * BS, trigger_point); packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = trigger_point; logic.unitsize = devc->prof->num_channels / 8; logic.data = devc->final_buf + (block * BS); sr_session_send(devc->cb_data, &packet); } /* Send the SR_DF_TRIGGER packet to the session bus. */ sr_spew("Sending SR_DF_TRIGGER packet, sample = %d.", (block * BS) + trigger_point); packet.type = SR_DF_TRIGGER; packet.payload = NULL; sr_session_send(devc->cb_data, &packet); /* If at least one sample is located after the trigger... */ if (trigger_point < (BS - 1)) { /* Send post-trigger SR_DF_LOGIC packet to the session bus. */ sr_spew("Sending post-trigger SR_DF_LOGIC packet, " "start = %d, length = %d.", (block * BS) + trigger_point, BS - trigger_point); packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = BS - trigger_point; logic.unitsize = devc->prof->num_channels / 8; logic.data = devc->final_buf + (block * BS) + trigger_point; sr_session_send(devc->cb_data, &packet); } } libsigrok-0.3.0/hardware/chronovu-la/api.c0000644000175000017500000003355712332246667015417 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2011-2014 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "protocol.h" SR_PRIV struct sr_dev_driver chronovu_la_driver_info; static struct sr_dev_driver *di = &chronovu_la_driver_info; static const int32_t hwcaps[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_SAMPLERATE, SR_CONF_TRIGGER_TYPE, SR_CONF_LIMIT_MSEC, /* TODO: Not yet implemented. */ SR_CONF_LIMIT_SAMPLES, /* TODO: Not yet implemented. */ }; /* The ChronoVu LA8/LA16 can have multiple VID/PID pairs. */ static struct { uint16_t vid; uint16_t pid; int model; const char *iproduct; } vid_pid[] = { { 0x0403, 0x6001, CHRONOVU_LA8, "ChronoVu LA8" }, { 0x0403, 0x8867, CHRONOVU_LA8, "ChronoVu LA8" }, { 0x0403, 0x6001, CHRONOVU_LA16, "ChronoVu LA16" }, { 0x0403, 0x8867, CHRONOVU_LA16, "ChronoVu LA16" }, }; static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data); static void clear_helper(void *priv) { struct dev_context *devc; devc = priv; ftdi_free(devc->ftdic); g_free(devc->final_buf); } static int dev_clear(void) { return std_dev_clear(di, clear_helper); } static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static int add_device(int idx, int model, GSList **devices) { int ret; unsigned int i; struct sr_dev_inst *sdi; struct drv_context *drvc; struct dev_context *devc; struct sr_channel *ch; ret = SR_OK; drvc = di->priv; /* Allocate memory for our private device context. */ devc = g_try_malloc(sizeof(struct dev_context)); /* Set some sane defaults. */ devc->prof = &cv_profiles[model]; devc->ftdic = NULL; /* Will be set in the open() API call. */ devc->cur_samplerate = 0; /* Set later (different for LA8/LA16). */ devc->limit_msec = 0; devc->limit_samples = 0; devc->cb_data = NULL; memset(devc->mangled_buf, 0, BS); devc->final_buf = NULL; devc->trigger_pattern = 0x0000; /* Irrelevant, see trigger_mask. */ devc->trigger_mask = 0x0000; /* All channels: "don't care". */ devc->trigger_edgemask = 0x0000; /* All channels: "state triggered". */ devc->trigger_found = 0; devc->done = 0; devc->block_counter = 0; devc->divcount = 0; devc->usb_vid = vid_pid[idx].vid; devc->usb_pid = vid_pid[idx].pid; memset(devc->samplerates, 0, sizeof(uint64_t) * 255); /* Allocate memory where we'll store the de-mangled data. */ if (!(devc->final_buf = g_try_malloc(SDRAM_SIZE))) { sr_err("Failed to allocate memory for sample buffer."); ret = SR_ERR_MALLOC; goto err_free_devc; } /* We now know the device, set its max. samplerate as default. */ devc->cur_samplerate = devc->prof->max_samplerate; /* Register the device with libsigrok. */ sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING, "ChronoVu", devc->prof->modelname, NULL); if (!sdi) { sr_err("Failed to create device instance."); ret = SR_ERR; goto err_free_final_buf; } sdi->driver = di; sdi->priv = devc; for (i = 0; i < devc->prof->num_channels; i++) { if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, cv_channel_names[i]))) { ret = SR_ERR; goto err_free_dev_inst; } sdi->channels = g_slist_append(sdi->channels, ch); } *devices = g_slist_append(*devices, sdi); drvc->instances = g_slist_append(drvc->instances, sdi); return SR_OK; err_free_dev_inst: sr_dev_inst_free(sdi); err_free_final_buf: g_free(devc->final_buf); err_free_devc: g_free(devc); return ret; } static GSList *scan(GSList *options) { int ret; unsigned int i; GSList *devices; struct ftdi_context *ftdic; (void)options; devices = NULL; /* Allocate memory for the FTDI context and initialize it. */ if (!(ftdic = ftdi_new())) { sr_err("Failed to initialize libftdi."); return NULL; } /* Check for LA8 and/or LA16 devices with various VID/PIDs. */ for (i = 0; i < ARRAY_SIZE(vid_pid); i++) { ret = ftdi_usb_open_desc(ftdic, vid_pid[i].vid, vid_pid[i].pid, vid_pid[i].iproduct, NULL); /* Show errors other than "device not found". */ if (ret < 0 && ret != -3) sr_dbg("Error finding/opening device (%d): %s.", ret, ftdi_get_error_string(ftdic)); if (ret < 0) continue; /* No device found, or not usable. */ sr_dbg("Found %s device (%04x:%04x).", vid_pid[i].iproduct, vid_pid[i].vid, vid_pid[i].pid); if ((ret = add_device(i, vid_pid[i].model, &devices)) < 0) sr_dbg("Failed to add device: %d.", ret); if ((ret = ftdi_usb_close(ftdic)) < 0) sr_dbg("Failed to close FTDI device (%d): %s.", ret, ftdi_get_error_string(ftdic)); } /* Close USB device, deinitialize and free the FTDI context. */ ftdi_free(ftdic); ftdic = NULL; return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; ret = SR_ERR; if (!(devc = sdi->priv)) return SR_ERR_BUG; /* Allocate memory for the FTDI context and initialize it. */ if (!(devc->ftdic = ftdi_new())) { sr_err("Failed to initialize libftdi."); return SR_ERR; } sr_dbg("Opening %s device (%04x:%04x).", devc->prof->modelname, devc->usb_vid, devc->usb_pid); /* Open the device. */ if ((ret = ftdi_usb_open_desc(devc->ftdic, devc->usb_vid, devc->usb_pid, devc->prof->iproduct, NULL)) < 0) { sr_err("Failed to open FTDI device (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); goto err_ftdi_free; } sr_dbg("Device opened successfully."); /* Purge RX/TX buffers in the FTDI chip. */ if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) { sr_err("Failed to purge FTDI buffers (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); goto err_ftdi_free; } sr_dbg("FTDI buffers purged successfully."); /* Enable flow control in the FTDI chip. */ if ((ret = ftdi_setflowctrl(devc->ftdic, SIO_RTS_CTS_HS)) < 0) { sr_err("Failed to enable FTDI flow control (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); goto err_ftdi_free; } sr_dbg("FTDI flow control enabled successfully."); /* Wait 100ms. */ g_usleep(100 * 1000); sdi->status = SR_ST_ACTIVE; return SR_OK; err_ftdi_free: ftdi_free(devc->ftdic); /* Close device (if open), free FTDI context. */ devc->ftdic = NULL; return ret; } static int dev_close(struct sr_dev_inst *sdi) { int ret; struct dev_context *devc; if (sdi->status != SR_ST_ACTIVE) return SR_OK; devc = sdi->priv; if (devc->ftdic && (ret = ftdi_usb_close(devc->ftdic)) < 0) sr_err("Failed to close FTDI device (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); sdi->status = SR_ST_INACTIVE; return SR_OK; } static int cleanup(void) { return dev_clear(); } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; switch (id) { case SR_CONF_SAMPLERATE: if (!sdi || !(devc = sdi->priv)) return SR_ERR_BUG; *data = g_variant_new_uint64(devc->cur_samplerate); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) return SR_ERR_BUG; switch (id) { case SR_CONF_SAMPLERATE: if (cv_set_samplerate(sdi, g_variant_get_uint64(data)) < 0) return SR_ERR; break; case SR_CONF_LIMIT_MSEC: if (g_variant_get_uint64(data) == 0) return SR_ERR_ARG; devc->limit_msec = g_variant_get_uint64(data); break; case SR_CONF_LIMIT_SAMPLES: if (g_variant_get_uint64(data) == 0) return SR_ERR_ARG; devc->limit_samples = g_variant_get_uint64(data); break; default: return SR_ERR_NA; } return SR_OK; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { GVariant *gvar, *grange[2]; GVariantBuilder gvb; struct dev_context *devc; (void)cg; switch (key) { case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; case SR_CONF_SAMPLERATE: if (!sdi || !sdi->priv || !(devc = sdi->priv)) return SR_ERR_BUG; cv_fill_samplerates_if_needed(sdi); g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), devc->samplerates, ARRAY_SIZE(devc->samplerates), sizeof(uint64_t)); g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; case SR_CONF_LIMIT_SAMPLES: if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof) return SR_ERR_BUG; grange[0] = g_variant_new_uint64(0); if (devc->prof->model == CHRONOVU_LA8) grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES); else grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES / 2); *data = g_variant_new_tuple(grange, 2); break; case SR_CONF_TRIGGER_TYPE: if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof) return SR_ERR_BUG; *data = g_variant_new_string(devc->prof->trigger_type); break; default: return SR_ERR_NA; } return SR_OK; } static int receive_data(int fd, int revents, void *cb_data) { int i, ret; struct sr_dev_inst *sdi; struct dev_context *devc; (void)fd; (void)revents; if (!(sdi = cb_data)) { sr_err("cb_data was NULL."); return FALSE; } if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return FALSE; } if (!devc->ftdic) { sr_err("devc->ftdic was NULL."); return FALSE; } /* Get one block of data. */ if ((ret = cv_read_block(devc)) < 0) { sr_err("Failed to read data block: %d.", ret); dev_acquisition_stop(sdi, sdi); return FALSE; } /* We need to get exactly NUM_BLOCKS blocks (i.e. 8MB) of data. */ if (devc->block_counter != (NUM_BLOCKS - 1)) { devc->block_counter++; return TRUE; } sr_dbg("Sampling finished, sending data to session bus now."); /* * All data was received and demangled, send it to the session bus. * * Note: Due to the method how data is spread across the 8MByte of * SDRAM, we can _not_ send it to the session bus in a streaming * manner while we receive it. We have to receive and de-mangle the * full 8MByte first, only then the whole buffer contains valid data. */ for (i = 0; i < NUM_BLOCKS; i++) cv_send_block_to_session_bus(devc, i); dev_acquisition_stop(sdi, sdi); return TRUE; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; uint8_t buf[8]; int bytes_to_write, bytes_written; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return SR_ERR_BUG; } if (!devc->ftdic) { sr_err("devc->ftdic was NULL."); return SR_ERR_BUG; } devc->divcount = cv_samplerate_to_divcount(sdi, devc->cur_samplerate); if (devc->divcount == 0xff) { sr_err("Invalid divcount/samplerate."); return SR_ERR; } if (cv_configure_channels(sdi) != SR_OK) { sr_err("Failed to configure channels."); return SR_ERR; } /* Fill acquisition parameters into buf[]. */ if (devc->prof->model == CHRONOVU_LA8) { buf[0] = devc->divcount; buf[1] = 0xff; /* This byte must always be 0xff. */ buf[2] = devc->trigger_pattern & 0xff; buf[3] = devc->trigger_mask & 0xff; bytes_to_write = 4; } else { buf[0] = devc->divcount; buf[1] = 0xff; /* This byte must always be 0xff. */ buf[2] = (devc->trigger_pattern & 0xff00) >> 8; /* LSB */ buf[3] = (devc->trigger_pattern & 0x00ff) >> 0; /* MSB */ buf[4] = (devc->trigger_mask & 0xff00) >> 8; /* LSB */ buf[5] = (devc->trigger_mask & 0x00ff) >> 0; /* MSB */ buf[6] = (devc->trigger_edgemask & 0xff00) >> 8; /* LSB */ buf[7] = (devc->trigger_edgemask & 0x00ff) >> 0; /* MSB */ bytes_to_write = 8; } /* Start acquisition. */ bytes_written = cv_write(devc, buf, bytes_to_write); if (bytes_written < 0 || bytes_written != bytes_to_write) { sr_err("Acquisition failed to start."); return SR_ERR; } sr_dbg("Hardware acquisition started successfully."); devc->cb_data = cb_data; /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* Time when we should be done (for detecting trigger timeouts). */ devc->done = (devc->divcount + 1) * devc->prof->trigger_constant + g_get_monotonic_time() + (10 * G_TIME_SPAN_SECOND); devc->block_counter = 0; devc->trigger_found = 0; /* Hook up a dummy handler to receive data from the device. */ sr_source_add(-1, G_IO_IN, 0, receive_data, (void *)sdi); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { struct sr_datafeed_packet packet; (void)sdi; sr_dbg("Stopping acquisition."); sr_source_remove(-1); /* Send end packet to the session bus. */ sr_dbg("Sending SR_DF_END."); packet.type = SR_DF_END; sr_session_send(cb_data, &packet); return SR_OK; } SR_PRIV struct sr_dev_driver chronovu_la_driver_info = { .name = "chronovu-la", .longname = "ChronoVu LA8/LA16", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = dev_clear, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/asix-sigma/0000755000175000017500000000000012332246734014345 500000000000000libsigrok-0.3.0/hardware/asix-sigma/asix-sigma.h0000644000175000017500000001126512332246667016512 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2010 Håvard Espeland , * Copyright (C) 2010 Martin Stensgård * Copyright (C) 2010 Carl Henrik Lunde * * 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 . */ #ifndef LIBSIGROK_HARDWARE_ASIX_SIGMA_ASIX_SIGMA_H #define LIBSIGROK_HARDWARE_ASIX_SIGMA_ASIX_SIGMA_H #define LOG_PREFIX "asix-sigma" enum sigma_write_register { WRITE_CLOCK_SELECT = 0, WRITE_TRIGGER_SELECT0 = 1, WRITE_TRIGGER_SELECT1 = 2, WRITE_MODE = 3, WRITE_MEMROW = 4, WRITE_POST_TRIGGER = 5, WRITE_TRIGGER_OPTION = 6, WRITE_PIN_VIEW = 7, WRITE_TEST = 15, }; enum sigma_read_register { READ_ID = 0, READ_TRIGGER_POS_LOW = 1, READ_TRIGGER_POS_HIGH = 2, READ_TRIGGER_POS_UP = 3, READ_STOP_POS_LOW = 4, READ_STOP_POS_HIGH = 5, READ_STOP_POS_UP = 6, READ_MODE = 7, READ_PIN_CHANGE_LOW = 8, READ_PIN_CHANGE_HIGH = 9, READ_BLOCK_LAST_TS_LOW = 10, READ_BLOCK_LAST_TS_HIGH = 11, READ_PIN_VIEW = 12, READ_TEST = 15, }; #define REG_ADDR_LOW (0x0 << 4) #define REG_ADDR_HIGH (0x1 << 4) #define REG_DATA_LOW (0x2 << 4) #define REG_DATA_HIGH_WRITE (0x3 << 4) #define REG_READ_ADDR (0x4 << 4) #define REG_DRAM_WAIT_ACK (0x5 << 4) /* Bit (1 << 4) can be low or high (double buffer / cache) */ #define REG_DRAM_BLOCK (0x6 << 4) #define REG_DRAM_BLOCK_BEGIN (0x8 << 4) #define REG_DRAM_BLOCK_DATA (0xa << 4) #define LEDSEL0 6 #define LEDSEL1 7 #define NEXT_REG 1 #define EVENTS_PER_CLUSTER 7 #define CHUNK_SIZE 1024 /* * The entire ASIX Sigma DRAM is an array of struct sigma_dram_line[1024]; */ /* One "DRAM cluster" contains a timestamp and 7 samples, 16b total. */ struct sigma_dram_cluster { uint8_t timestamp_lo; uint8_t timestamp_hi; struct { uint8_t sample_hi; uint8_t sample_lo; } samples[7]; }; /* One "DRAM line" contains 64 "DRAM clusters", 1024b total. */ struct sigma_dram_line { struct sigma_dram_cluster cluster[64]; }; struct clockselect_50 { uint8_t async; uint8_t fraction; uint16_t disabled_channels; }; /* The effect of all these are still a bit unclear. */ struct triggerinout { uint8_t trgout_resistor_enable : 1; uint8_t trgout_resistor_pullup : 1; uint8_t reserved1 : 1; uint8_t trgout_bytrigger : 1; uint8_t trgout_byevent : 1; uint8_t trgout_bytriggerin : 1; uint8_t reserved2 : 2; /* Should be set same as the first two */ uint8_t trgout_resistor_enable2 : 1; uint8_t trgout_resistor_pullup2 : 1; uint8_t reserved3 : 1; uint8_t trgout_long : 1; uint8_t trgout_pin : 1; /* Use 1k resistor. Pullup? */ uint8_t trgin_negate : 1; uint8_t trgout_enable : 1; uint8_t trgin_enable : 1; }; struct triggerlut { /* The actual LUTs. */ uint16_t m0d[4], m1d[4], m2d[4]; uint16_t m3, m3s, m4; /* Paramters should be sent as a single register write. */ struct { uint8_t selc : 2; uint8_t selpresc : 6; uint8_t selinc : 2; uint8_t selres : 2; uint8_t sela : 2; uint8_t selb : 2; uint16_t cmpb; uint16_t cmpa; } params; }; /* Trigger configuration */ struct sigma_trigger { /* Only two channels can be used in mask. */ uint16_t risingmask; uint16_t fallingmask; /* Simple trigger support (<= 50 MHz). */ uint16_t simplemask; uint16_t simplevalue; /* TODO: Advanced trigger support (boolean expressions). */ }; /* Events for trigger operation. */ enum triggerop { OP_LEVEL = 1, OP_NOT, OP_RISE, OP_FALL, OP_RISEFALL, OP_NOTRISE, OP_NOTFALL, OP_NOTRISEFALL, }; /* Logical functions for trigger operation. */ enum triggerfunc { FUNC_AND = 1, FUNC_NAND, FUNC_OR, FUNC_NOR, FUNC_XOR, FUNC_NXOR, }; struct sigma_state { enum { SIGMA_UNINITIALIZED = 0, SIGMA_IDLE, SIGMA_CAPTURE, SIGMA_DOWNLOAD, } state; uint16_t lastts; uint16_t lastsample; }; /* Private, per-device-instance driver context. */ struct dev_context { struct ftdi_context ftdic; uint64_t cur_samplerate; uint64_t period_ps; uint64_t limit_msec; struct timeval start_tv; int cur_firmware; int num_channels; int cur_channels; int samples_per_event; int capture_ratio; struct sigma_trigger trigger; int use_triggers; struct sigma_state state; void *cb_data; }; #endif libsigrok-0.3.0/hardware/asix-sigma/asix-sigma.c0000644000175000017500000011232212332246667016501 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2010-2012 Håvard Espeland , * Copyright (C) 2010 Martin Stensgård * Copyright (C) 2010 Carl Henrik Lunde * * 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 . */ /* * ASIX SIGMA/SIGMA2 logic analyzer driver */ #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "asix-sigma.h" #define USB_VENDOR 0xa600 #define USB_PRODUCT 0xa000 #define USB_DESCRIPTION "ASIX SIGMA" #define USB_VENDOR_NAME "ASIX" #define USB_MODEL_NAME "SIGMA" #define TRIGGER_TYPE "rf10" SR_PRIV struct sr_dev_driver asix_sigma_driver_info; static struct sr_dev_driver *di = &asix_sigma_driver_info; static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data); /* * The ASIX Sigma supports arbitrary integer frequency divider in * the 50MHz mode. The divider is in range 1...256 , allowing for * very precise sampling rate selection. This driver supports only * a subset of the sampling rates. */ static const uint64_t samplerates[] = { SR_KHZ(200), /* div=250 */ SR_KHZ(250), /* div=200 */ SR_KHZ(500), /* div=100 */ SR_MHZ(1), /* div=50 */ SR_MHZ(5), /* div=10 */ SR_MHZ(10), /* div=5 */ SR_MHZ(25), /* div=2 */ SR_MHZ(50), /* div=1 */ SR_MHZ(100), /* Special FW needed */ SR_MHZ(200), /* Special FW needed */ }; /* * Channel numbers seem to go from 1-16, according to this image: * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg * (the cable has two additional GND pins, and a TI and TO pin) */ static const char *channel_names[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", }; static const int32_t hwcaps[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_SAMPLERATE, SR_CONF_TRIGGER_TYPE, SR_CONF_CAPTURE_RATIO, SR_CONF_LIMIT_MSEC, }; static const char *sigma_firmware_files[] = { /* 50 MHz, supports 8 bit fractions */ FIRMWARE_DIR "/asix-sigma-50.fw", /* 100 MHz */ FIRMWARE_DIR "/asix-sigma-100.fw", /* 200 MHz */ FIRMWARE_DIR "/asix-sigma-200.fw", /* Synchronous clock from pin */ FIRMWARE_DIR "/asix-sigma-50sync.fw", /* Frequency counter */ FIRMWARE_DIR "/asix-sigma-phasor.fw", }; static int sigma_read(void *buf, size_t size, struct dev_context *devc) { int ret; ret = ftdi_read_data(&devc->ftdic, (unsigned char *)buf, size); if (ret < 0) { sr_err("ftdi_read_data failed: %s", ftdi_get_error_string(&devc->ftdic)); } return ret; } static int sigma_write(void *buf, size_t size, struct dev_context *devc) { int ret; ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size); if (ret < 0) { sr_err("ftdi_write_data failed: %s", ftdi_get_error_string(&devc->ftdic)); } else if ((size_t) ret != size) { sr_err("ftdi_write_data did not complete write."); } return ret; } static int sigma_write_register(uint8_t reg, uint8_t *data, size_t len, struct dev_context *devc) { size_t i; uint8_t buf[len + 2]; int idx = 0; buf[idx++] = REG_ADDR_LOW | (reg & 0xf); buf[idx++] = REG_ADDR_HIGH | (reg >> 4); for (i = 0; i < len; ++i) { buf[idx++] = REG_DATA_LOW | (data[i] & 0xf); buf[idx++] = REG_DATA_HIGH_WRITE | (data[i] >> 4); } return sigma_write(buf, idx, devc); } static int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc) { return sigma_write_register(reg, &value, 1, devc); } static int sigma_read_register(uint8_t reg, uint8_t *data, size_t len, struct dev_context *devc) { uint8_t buf[3]; buf[0] = REG_ADDR_LOW | (reg & 0xf); buf[1] = REG_ADDR_HIGH | (reg >> 4); buf[2] = REG_READ_ADDR; sigma_write(buf, sizeof(buf), devc); return sigma_read(data, len, devc); } static uint8_t sigma_get_register(uint8_t reg, struct dev_context *devc) { uint8_t value; if (1 != sigma_read_register(reg, &value, 1, devc)) { sr_err("sigma_get_register: 1 byte expected"); return 0; } return value; } static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos, struct dev_context *devc) { uint8_t buf[] = { REG_ADDR_LOW | READ_TRIGGER_POS_LOW, REG_READ_ADDR | NEXT_REG, REG_READ_ADDR | NEXT_REG, REG_READ_ADDR | NEXT_REG, REG_READ_ADDR | NEXT_REG, REG_READ_ADDR | NEXT_REG, REG_READ_ADDR | NEXT_REG, }; uint8_t result[6]; sigma_write(buf, sizeof(buf), devc); sigma_read(result, sizeof(result), devc); *triggerpos = result[0] | (result[1] << 8) | (result[2] << 16); *stoppos = result[3] | (result[4] << 8) | (result[5] << 16); /* Not really sure why this must be done, but according to spec. */ if ((--*stoppos & 0x1ff) == 0x1ff) stoppos -= 64; if ((*--triggerpos & 0x1ff) == 0x1ff) triggerpos -= 64; return 1; } static int sigma_read_dram(uint16_t startchunk, size_t numchunks, uint8_t *data, struct dev_context *devc) { size_t i; uint8_t buf[4096]; int idx = 0; /* Send the startchunk. Index start with 1. */ buf[0] = startchunk >> 8; buf[1] = startchunk & 0xff; sigma_write_register(WRITE_MEMROW, buf, 2, devc); /* Read the DRAM. */ buf[idx++] = REG_DRAM_BLOCK; buf[idx++] = REG_DRAM_WAIT_ACK; for (i = 0; i < numchunks; ++i) { /* Alternate bit to copy from DRAM to cache. */ if (i != (numchunks - 1)) buf[idx++] = REG_DRAM_BLOCK | (((i + 1) % 2) << 4); buf[idx++] = REG_DRAM_BLOCK_DATA | ((i % 2) << 4); if (i != (numchunks - 1)) buf[idx++] = REG_DRAM_WAIT_ACK; } sigma_write(buf, idx, devc); return sigma_read(data, numchunks * CHUNK_SIZE, devc); } /* Upload trigger look-up tables to Sigma. */ static int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc) { int i; uint8_t tmp[2]; uint16_t bit; /* Transpose the table and send to Sigma. */ for (i = 0; i < 16; ++i) { bit = 1 << i; tmp[0] = tmp[1] = 0; if (lut->m2d[0] & bit) tmp[0] |= 0x01; if (lut->m2d[1] & bit) tmp[0] |= 0x02; if (lut->m2d[2] & bit) tmp[0] |= 0x04; if (lut->m2d[3] & bit) tmp[0] |= 0x08; if (lut->m3 & bit) tmp[0] |= 0x10; if (lut->m3s & bit) tmp[0] |= 0x20; if (lut->m4 & bit) tmp[0] |= 0x40; if (lut->m0d[0] & bit) tmp[1] |= 0x01; if (lut->m0d[1] & bit) tmp[1] |= 0x02; if (lut->m0d[2] & bit) tmp[1] |= 0x04; if (lut->m0d[3] & bit) tmp[1] |= 0x08; if (lut->m1d[0] & bit) tmp[1] |= 0x10; if (lut->m1d[1] & bit) tmp[1] |= 0x20; if (lut->m1d[2] & bit) tmp[1] |= 0x40; if (lut->m1d[3] & bit) tmp[1] |= 0x80; sigma_write_register(WRITE_TRIGGER_SELECT0, tmp, sizeof(tmp), devc); sigma_set_register(WRITE_TRIGGER_SELECT1, 0x30 | i, devc); } /* Send the parameters */ sigma_write_register(WRITE_TRIGGER_SELECT0, (uint8_t *) &lut->params, sizeof(lut->params), devc); return SR_OK; } static void clear_helper(void *priv) { struct dev_context *devc; devc = priv; ftdi_deinit(&devc->ftdic); } static int dev_clear(void) { return std_dev_clear(di, clear_helper); } static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct sr_dev_inst *sdi; struct sr_channel *ch; struct drv_context *drvc; struct dev_context *devc; GSList *devices; struct ftdi_device_list *devlist; char serial_txt[10]; uint32_t serial; int ret; unsigned int i; (void)options; drvc = di->priv; devices = NULL; if (!(devc = g_try_malloc(sizeof(struct dev_context)))) { sr_err("%s: devc malloc failed", __func__); return NULL; } ftdi_init(&devc->ftdic); /* Look for SIGMAs. */ if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist, USB_VENDOR, USB_PRODUCT)) <= 0) { if (ret < 0) sr_err("ftdi_usb_find_all(): %d", ret); goto free; } /* Make sure it's a version 1 or 2 SIGMA. */ ftdi_usb_get_strings(&devc->ftdic, devlist->dev, NULL, 0, NULL, 0, serial_txt, sizeof(serial_txt)); sscanf(serial_txt, "%x", &serial); if (serial < 0xa6010000 || serial > 0xa602ffff) { sr_err("Only SIGMA and SIGMA2 are supported " "in this version of libsigrok."); goto free; } sr_info("Found ASIX SIGMA - Serial: %s", serial_txt); devc->cur_samplerate = samplerates[0]; devc->period_ps = 0; devc->limit_msec = 0; devc->cur_firmware = -1; devc->num_channels = 0; devc->samples_per_event = 0; devc->capture_ratio = 50; devc->use_triggers = 0; /* Register SIGMA device. */ if (!(sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING, USB_VENDOR_NAME, USB_MODEL_NAME, NULL))) { sr_err("%s: sdi was NULL", __func__); goto free; } sdi->driver = di; for (i = 0; i < ARRAY_SIZE(channel_names); i++) { ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]); if (!ch) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); } devices = g_slist_append(devices, sdi); drvc->instances = g_slist_append(drvc->instances, sdi); sdi->priv = devc; /* We will open the device again when we need it. */ ftdi_list_free(&devlist); return devices; free: ftdi_deinit(&devc->ftdic); g_free(devc); return NULL; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } /* * Configure the FPGA for bitbang mode. * This sequence is documented in section 2. of the ASIX Sigma programming * manual. This sequence is necessary to configure the FPGA in the Sigma * into Bitbang mode, in which it can be programmed with the firmware. */ static int sigma_fpga_init_bitbang(struct dev_context *devc) { uint8_t suicide[] = { 0x84, 0x84, 0x88, 0x84, 0x88, 0x84, 0x88, 0x84, }; uint8_t init_array[] = { 0x01, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, }; int i, ret, timeout = 10000; uint8_t data; /* Section 2. part 1), do the FPGA suicide. */ sigma_write(suicide, sizeof(suicide), devc); sigma_write(suicide, sizeof(suicide), devc); sigma_write(suicide, sizeof(suicide), devc); sigma_write(suicide, sizeof(suicide), devc); /* Section 2. part 2), do pulse on D1. */ sigma_write(init_array, sizeof(init_array), devc); ftdi_usb_purge_buffers(&devc->ftdic); /* Wait until the FPGA asserts D6/INIT_B. */ for (i = 0; i < timeout; i++) { ret = sigma_read(&data, 1, devc); if (ret < 0) return ret; /* Test if pin D6 got asserted. */ if (data & (1 << 5)) return 0; /* The D6 was not asserted yet, wait a bit. */ usleep(10000); } return SR_ERR_TIMEOUT; } /* * Configure the FPGA for logic-analyzer mode. */ static int sigma_fpga_init_la(struct dev_context *devc) { /* Initialize the logic analyzer mode. */ uint8_t logic_mode_start[] = { REG_ADDR_LOW | (READ_ID & 0xf), REG_ADDR_HIGH | (READ_ID >> 8), REG_READ_ADDR, /* Read ID register. */ REG_ADDR_LOW | (WRITE_TEST & 0xf), REG_DATA_LOW | 0x5, REG_DATA_HIGH_WRITE | 0x5, REG_READ_ADDR, /* Read scratch register. */ REG_DATA_LOW | 0xa, REG_DATA_HIGH_WRITE | 0xa, REG_READ_ADDR, /* Read scratch register. */ REG_ADDR_LOW | (WRITE_MODE & 0xf), REG_DATA_LOW | 0x0, REG_DATA_HIGH_WRITE | 0x8, }; uint8_t result[3]; int ret; /* Initialize the logic analyzer mode. */ sigma_write(logic_mode_start, sizeof(logic_mode_start), devc); /* Expect a 3 byte reply since we issued three READ requests. */ ret = sigma_read(result, 3, devc); if (ret != 3) goto err; if (result[0] != 0xa6 || result[1] != 0x55 || result[2] != 0xaa) goto err; return SR_OK; err: sr_err("Configuration failed. Invalid reply received."); return SR_ERR; } /* * Read the firmware from a file and transform it into a series of bitbang * pulses used to program the FPGA. Note that the *bb_cmd must be free()'d * by the caller of this function. */ static int sigma_fw_2_bitbang(const char *filename, uint8_t **bb_cmd, gsize *bb_cmd_size) { GMappedFile *file; GError *error; gsize i, file_size, bb_size; gchar *firmware; uint8_t *bb_stream, *bbs; uint32_t imm; int bit, v; int ret = SR_OK; /* * Map the file and make the mapped buffer writable. * NOTE: Using writable=TRUE does _NOT_ mean that file that is mapped * will be modified. It will not be modified until someone uses * g_file_set_contents() on it. */ error = NULL; file = g_mapped_file_new(filename, TRUE, &error); g_assert_no_error(error); file_size = g_mapped_file_get_length(file); firmware = g_mapped_file_get_contents(file); g_assert(firmware); /* Weird magic transformation below, I have no idea what it does. */ imm = 0x3f6df2ab; for (i = 0; i < file_size; i++) { imm = (imm + 0xa853753) % 177 + (imm * 0x8034052); firmware[i] ^= imm & 0xff; } /* * Now that the firmware is "transformed", we will transcribe the * firmware blob into a sequence of toggles of the Dx wires. This * sequence will be fed directly into the Sigma, which must be in * the FPGA bitbang programming mode. */ /* Each bit of firmware is transcribed as two toggles of Dx wires. */ bb_size = file_size * 8 * 2; bb_stream = (uint8_t *)g_try_malloc(bb_size); if (!bb_stream) { sr_err("%s: Failed to allocate bitbang stream", __func__); ret = SR_ERR_MALLOC; goto exit; } bbs = bb_stream; for (i = 0; i < file_size; i++) { for (bit = 7; bit >= 0; bit--) { v = (firmware[i] & (1 << bit)) ? 0x40 : 0x00; *bbs++ = v | 0x01; *bbs++ = v; } } /* The transformation completed successfully, return the result. */ *bb_cmd = bb_stream; *bb_cmd_size = bb_size; exit: g_mapped_file_unref(file); return ret; } static int upload_firmware(int firmware_idx, struct dev_context *devc) { int ret; unsigned char *buf; unsigned char pins; size_t buf_size; const char *firmware = sigma_firmware_files[firmware_idx]; struct ftdi_context *ftdic = &devc->ftdic; /* Make sure it's an ASIX SIGMA. */ ret = ftdi_usb_open_desc(ftdic, USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL); if (ret < 0) { sr_err("ftdi_usb_open failed: %s", ftdi_get_error_string(ftdic)); return 0; } ret = ftdi_set_bitmode(ftdic, 0xdf, BITMODE_BITBANG); if (ret < 0) { sr_err("ftdi_set_bitmode failed: %s", ftdi_get_error_string(ftdic)); return 0; } /* Four times the speed of sigmalogan - Works well. */ ret = ftdi_set_baudrate(ftdic, 750000); if (ret < 0) { sr_err("ftdi_set_baudrate failed: %s", ftdi_get_error_string(ftdic)); return 0; } /* Initialize the FPGA for firmware upload. */ ret = sigma_fpga_init_bitbang(devc); if (ret) return ret; /* Prepare firmware. */ ret = sigma_fw_2_bitbang(firmware, &buf, &buf_size); if (ret != SR_OK) { sr_err("An error occured while reading the firmware: %s", firmware); return ret; } /* Upload firmare. */ sr_info("Uploading firmware file '%s'.", firmware); sigma_write(buf, buf_size, devc); g_free(buf); ret = ftdi_set_bitmode(ftdic, 0x00, BITMODE_RESET); if (ret < 0) { sr_err("ftdi_set_bitmode failed: %s", ftdi_get_error_string(ftdic)); return SR_ERR; } ftdi_usb_purge_buffers(ftdic); /* Discard garbage. */ while (sigma_read(&pins, 1, devc) == 1) ; /* Initialize the FPGA for logic-analyzer mode. */ ret = sigma_fpga_init_la(devc); if (ret != SR_OK) return ret; devc->cur_firmware = firmware_idx; sr_info("Firmware uploaded."); return SR_OK; } static int dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; devc = sdi->priv; /* Make sure it's an ASIX SIGMA. */ if ((ret = ftdi_usb_open_desc(&devc->ftdic, USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) { sr_err("ftdi_usb_open failed: %s", ftdi_get_error_string(&devc->ftdic)); return 0; } sdi->status = SR_ST_ACTIVE; return SR_OK; } static int set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate) { struct dev_context *devc; unsigned int i; int ret; devc = sdi->priv; ret = SR_OK; for (i = 0; i < ARRAY_SIZE(samplerates); i++) { if (samplerates[i] == samplerate) break; } if (samplerates[i] == 0) return SR_ERR_SAMPLERATE; if (samplerate <= SR_MHZ(50)) { ret = upload_firmware(0, devc); devc->num_channels = 16; } else if (samplerate == SR_MHZ(100)) { ret = upload_firmware(1, devc); devc->num_channels = 8; } else if (samplerate == SR_MHZ(200)) { ret = upload_firmware(2, devc); devc->num_channels = 4; } if (ret == SR_OK) { devc->cur_samplerate = samplerate; devc->period_ps = 1000000000000ULL / samplerate; devc->samples_per_event = 16 / devc->num_channels; devc->state.state = SIGMA_IDLE; } return ret; } /* * In 100 and 200 MHz mode, only a single pin rising/falling can be * set as trigger. In other modes, two rising/falling triggers can be set, * in addition to value/mask trigger for any number of channels. * * The Sigma supports complex triggers using boolean expressions, but this * has not been implemented yet. */ static int configure_channels(const struct sr_dev_inst *sdi) { struct dev_context *devc = sdi->priv; const struct sr_channel *ch; const GSList *l; int trigger_set = 0; int channelbit; memset(&devc->trigger, 0, sizeof(struct sigma_trigger)); for (l = sdi->channels; l; l = l->next) { ch = (struct sr_channel *)l->data; channelbit = 1 << (ch->index); if (!ch->enabled || !ch->trigger) continue; if (devc->cur_samplerate >= SR_MHZ(100)) { /* Fast trigger support. */ if (trigger_set) { sr_err("Only a single pin trigger in 100 and " "200MHz mode is supported."); return SR_ERR; } if (ch->trigger[0] == 'f') devc->trigger.fallingmask |= channelbit; else if (ch->trigger[0] == 'r') devc->trigger.risingmask |= channelbit; else { sr_err("Only rising/falling trigger in 100 " "and 200MHz mode is supported."); return SR_ERR; } ++trigger_set; } else { /* Simple trigger support (event). */ if (ch->trigger[0] == '1') { devc->trigger.simplevalue |= channelbit; devc->trigger.simplemask |= channelbit; } else if (ch->trigger[0] == '0') { devc->trigger.simplevalue &= ~channelbit; devc->trigger.simplemask |= channelbit; } else if (ch->trigger[0] == 'f') { devc->trigger.fallingmask |= channelbit; ++trigger_set; } else if (ch->trigger[0] == 'r') { devc->trigger.risingmask |= channelbit; ++trigger_set; } /* * Actually, Sigma supports 2 rising/falling triggers, * but they are ORed and the current trigger syntax * does not permit ORed triggers. */ if (trigger_set > 1) { sr_err("Only 1 rising/falling trigger " "is supported."); return SR_ERR; } } if (trigger_set) devc->use_triggers = 1; } return SR_OK; } static int dev_close(struct sr_dev_inst *sdi) { struct dev_context *devc; devc = sdi->priv; /* TODO */ if (sdi->status == SR_ST_ACTIVE) ftdi_usb_close(&devc->ftdic); sdi->status = SR_ST_INACTIVE; return SR_OK; } static int cleanup(void) { return dev_clear(); } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; if (!sdi) return SR_ERR; devc = sdi->priv; switch (id) { case SR_CONF_SAMPLERATE: *data = g_variant_new_uint64(devc->cur_samplerate); break; case SR_CONF_LIMIT_MSEC: *data = g_variant_new_uint64(devc->limit_msec); break; case SR_CONF_CAPTURE_RATIO: *data = g_variant_new_uint64(devc->capture_ratio); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; uint64_t tmp; int ret; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; ret = SR_OK; switch (id) { case SR_CONF_SAMPLERATE: ret = set_samplerate(sdi, g_variant_get_uint64(data)); break; case SR_CONF_LIMIT_MSEC: tmp = g_variant_get_uint64(data); if (tmp > 0) devc->limit_msec = g_variant_get_uint64(data); else ret = SR_ERR; break; case SR_CONF_LIMIT_SAMPLES: tmp = g_variant_get_uint64(data); devc->limit_msec = tmp * 1000 / devc->cur_samplerate; break; case SR_CONF_CAPTURE_RATIO: tmp = g_variant_get_uint64(data); if (tmp <= 100) devc->capture_ratio = tmp; else ret = SR_ERR; break; default: ret = SR_ERR_NA; } return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { GVariant *gvar; GVariantBuilder gvb; (void)sdi; (void)cg; switch (key) { case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; 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)); g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; case SR_CONF_TRIGGER_TYPE: *data = g_variant_new_string(TRIGGER_TYPE); break; default: return SR_ERR_NA; } return SR_OK; } /* Software trigger to determine exact trigger position. */ static int get_trigger_offset(uint8_t *samples, uint16_t last_sample, struct sigma_trigger *t) { int i; uint16_t sample = 0; for (i = 0; i < 8; ++i) { if (i > 0) last_sample = sample; sample = samples[2 * i] | (samples[2 * i + 1] << 8); /* Simple triggers. */ if ((sample & t->simplemask) != t->simplevalue) continue; /* Rising edge. */ if (((last_sample & t->risingmask) != 0) || ((sample & t->risingmask) != t->risingmask)) continue; /* Falling edge. */ if ((last_sample & t->fallingmask) != t->fallingmask || (sample & t->fallingmask) != 0) continue; break; } /* If we did not match, return original trigger pos. */ return i & 0x7; } /* * Return the timestamp of "DRAM cluster". */ static uint16_t sigma_dram_cluster_ts(struct sigma_dram_cluster *cluster) { return (cluster->timestamp_hi << 8) | cluster->timestamp_lo; } static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster, unsigned int events_in_cluster, unsigned int triggered, struct sr_dev_inst *sdi) { struct dev_context *devc = sdi->priv; struct sigma_state *ss = &devc->state; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; uint16_t tsdiff, ts; uint8_t samples[2048]; unsigned int i; ts = sigma_dram_cluster_ts(dram_cluster); tsdiff = ts - ss->lastts; ss->lastts = ts; packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.unitsize = 2; logic.data = samples; /* * First of all, send Sigrok a copy of the last sample from * previous cluster as many times as needed to make up for * the differential characteristics of data we get from the * Sigma. Sigrok needs one sample of data per period. * * One DRAM cluster contains a timestamp and seven samples, * the units of timestamp are "devc->period_ps" , the first * sample in the cluster happens at the time of the timestamp * and the remaining samples happen at timestamp +1...+6 . */ for (ts = 0; ts < tsdiff - (EVENTS_PER_CLUSTER - 1); ts++) { i = ts % 1024; samples[2 * i + 0] = ss->lastsample & 0xff; samples[2 * i + 1] = ss->lastsample >> 8; /* * If we have 1024 samples ready or we're at the * end of submitting the padding samples, submit * the packet to Sigrok. */ if ((i == 1023) || (ts == (tsdiff - EVENTS_PER_CLUSTER))) { logic.length = (i + 1) * logic.unitsize; sr_session_send(devc->cb_data, &packet); } } /* * Parse the samples in current cluster and prepare them * to be submitted to Sigrok. */ for (i = 0; i < events_in_cluster; i++) { samples[2 * i + 1] = dram_cluster->samples[i].sample_lo; samples[2 * i + 0] = dram_cluster->samples[i].sample_hi; } /* Send data up to trigger point (if triggered). */ int trigger_offset = 0; if (triggered) { /* * Trigger is not always accurate to sample because of * pipeline delay. However, it always triggers before * the actual event. We therefore look at the next * samples to pinpoint the exact position of the trigger. */ trigger_offset = get_trigger_offset(samples, ss->lastsample, &devc->trigger); if (trigger_offset > 0) { packet.type = SR_DF_LOGIC; logic.length = trigger_offset * logic.unitsize; sr_session_send(devc->cb_data, &packet); events_in_cluster -= trigger_offset; } /* Only send trigger if explicitly enabled. */ if (devc->use_triggers) { packet.type = SR_DF_TRIGGER; sr_session_send(devc->cb_data, &packet); } } if (events_in_cluster > 0) { packet.type = SR_DF_LOGIC; logic.length = events_in_cluster * logic.unitsize; logic.data = samples + (trigger_offset * logic.unitsize); sr_session_send(devc->cb_data, &packet); } ss->lastsample = samples[2 * (events_in_cluster - 1) + 0] | (samples[2 * (events_in_cluster - 1) + 1] << 8); } /* * Decode chunk of 1024 bytes, 64 clusters, 7 events per cluster. * Each event is 20ns apart, and can contain multiple samples. * * For 200 MHz, events contain 4 samples for each channel, spread 5 ns apart. * For 100 MHz, events contain 2 samples for each channel, spread 10 ns apart. * For 50 MHz and below, events contain one sample for each channel, * spread 20 ns apart. */ static int decode_chunk_ts(struct sigma_dram_line *dram_line, uint16_t events_in_line, uint32_t trigger_event, void *cb_data) { struct sigma_dram_cluster *dram_cluster; struct sr_dev_inst *sdi = cb_data; struct dev_context *devc = sdi->priv; unsigned int clusters_in_line = (events_in_line + (EVENTS_PER_CLUSTER - 1)) / EVENTS_PER_CLUSTER; unsigned int events_in_cluster; unsigned int i; uint32_t trigger_cluster = ~0, triggered = 0; /* Check if trigger is in this chunk. */ if (trigger_event < (64 * 7)) { if (devc->cur_samplerate <= SR_MHZ(50)) { trigger_event -= MIN(EVENTS_PER_CLUSTER - 1, trigger_event); } /* Find in which cluster the trigger occured. */ trigger_cluster = trigger_event / EVENTS_PER_CLUSTER; } /* For each full DRAM cluster. */ for (i = 0; i < clusters_in_line; i++) { dram_cluster = &dram_line->cluster[i]; /* The last cluster might not be full. */ if ((i == clusters_in_line - 1) && (events_in_line % EVENTS_PER_CLUSTER)) { events_in_cluster = events_in_line % EVENTS_PER_CLUSTER; } else { events_in_cluster = EVENTS_PER_CLUSTER; } triggered = (i == trigger_cluster); sigma_decode_dram_cluster(dram_cluster, events_in_cluster, triggered, sdi); } return SR_OK; } static int download_capture(struct sr_dev_inst *sdi) { struct dev_context *devc = sdi->priv; const int chunks_per_read = 32; struct sigma_dram_line *dram_line; int bufsz; uint32_t stoppos, triggerpos; struct sr_datafeed_packet packet; uint8_t modestatus; uint32_t i; uint32_t dl_lines_total, dl_lines_curr, dl_lines_done; uint32_t dl_events_in_line = 64 * 7; uint32_t trg_line = ~0, trg_event = ~0; dram_line = g_try_malloc0(chunks_per_read * sizeof(*dram_line)); if (!dram_line) return FALSE; sr_info("Downloading sample data."); /* Stop acquisition. */ sigma_set_register(WRITE_MODE, 0x11, devc); /* Set SDRAM Read Enable. */ sigma_set_register(WRITE_MODE, 0x02, devc); /* Get the current position. */ sigma_read_pos(&stoppos, &triggerpos, devc); /* Check if trigger has fired. */ modestatus = sigma_get_register(READ_MODE, devc); if (modestatus & 0x20) { trg_line = triggerpos >> 9; trg_event = triggerpos & 0x1ff; } /* * Determine how many 1024b "DRAM lines" do we need to read from the * Sigma so we have a complete set of samples. Note that the last * line can be only partial, containing less than 64 clusters. */ dl_lines_total = (stoppos >> 9) + 1; dl_lines_done = 0; while (dl_lines_total > dl_lines_done) { /* We can download only up-to 32 DRAM lines in one go! */ dl_lines_curr = MIN(chunks_per_read, dl_lines_total); bufsz = sigma_read_dram(dl_lines_done, dl_lines_curr, (uint8_t *)dram_line, devc); /* TODO: Check bufsz. For now, just avoid compiler warnings. */ (void)bufsz; /* This is the first DRAM line, so find the initial timestamp. */ if (dl_lines_done == 0) { devc->state.lastts = sigma_dram_cluster_ts(&dram_line[0].cluster[0]); devc->state.lastsample = 0; } for (i = 0; i < dl_lines_curr; i++) { uint32_t trigger_event = ~0; /* The last "DRAM line" can be only partially full. */ if (dl_lines_done + i == dl_lines_total - 1) dl_events_in_line = stoppos & 0x1ff; /* Test if the trigger happened on this line. */ if (dl_lines_done + i == trg_line) trigger_event = trg_event; decode_chunk_ts(dram_line + i, dl_events_in_line, trigger_event, sdi); } dl_lines_done += dl_lines_curr; } /* All done. */ packet.type = SR_DF_END; sr_session_send(sdi, &packet); dev_acquisition_stop(sdi, sdi); g_free(dram_line); return TRUE; } /* * Handle the Sigma when in CAPTURE mode. This function checks: * - Sampling time ended * - DRAM capacity overflow * This function triggers download of the samples from Sigma * in case either of the above conditions is true. */ static int sigma_capture_mode(struct sr_dev_inst *sdi) { struct dev_context *devc = sdi->priv; uint64_t running_msec; struct timeval tv; uint32_t stoppos, triggerpos; /* Check if the selected sampling duration passed. */ gettimeofday(&tv, 0); running_msec = (tv.tv_sec - devc->start_tv.tv_sec) * 1000 + (tv.tv_usec - devc->start_tv.tv_usec) / 1000; if (running_msec >= devc->limit_msec) return download_capture(sdi); /* Get the position in DRAM to which the FPGA is writing now. */ sigma_read_pos(&stoppos, &triggerpos, devc); /* Test if DRAM is full and if so, download the data. */ if ((stoppos >> 9) == 32767) return download_capture(sdi); return TRUE; } static int receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; (void)fd; (void)revents; sdi = cb_data; devc = sdi->priv; if (devc->state.state == SIGMA_IDLE) return TRUE; if (devc->state.state == SIGMA_CAPTURE) return sigma_capture_mode(sdi); return TRUE; } /* Build a LUT entry used by the trigger functions. */ static void build_lut_entry(uint16_t value, uint16_t mask, uint16_t *entry) { int i, j, k, bit; /* For each quad channel. */ for (i = 0; i < 4; ++i) { entry[i] = 0xffff; /* For each bit in LUT. */ for (j = 0; j < 16; ++j) /* For each channel in quad. */ for (k = 0; k < 4; ++k) { bit = 1 << (i * 4 + k); /* Set bit in entry */ if ((mask & bit) && ((!(value & bit)) != (!(j & (1 << k))))) entry[i] &= ~(1 << j); } } } /* Add a logical function to LUT mask. */ static void add_trigger_function(enum triggerop oper, enum triggerfunc func, int index, int neg, uint16_t *mask) { int i, j; int x[2][2], tmp, a, b, aset, bset, rset; memset(x, 0, 4 * sizeof(int)); /* Trigger detect condition. */ switch (oper) { case OP_LEVEL: x[0][1] = 1; x[1][1] = 1; break; case OP_NOT: x[0][0] = 1; x[1][0] = 1; break; case OP_RISE: x[0][1] = 1; break; case OP_FALL: x[1][0] = 1; break; case OP_RISEFALL: x[0][1] = 1; x[1][0] = 1; break; case OP_NOTRISE: x[1][1] = 1; x[0][0] = 1; x[1][0] = 1; break; case OP_NOTFALL: x[1][1] = 1; x[0][0] = 1; x[0][1] = 1; break; case OP_NOTRISEFALL: x[1][1] = 1; x[0][0] = 1; break; } /* Transpose if neg is set. */ if (neg) { for (i = 0; i < 2; ++i) { for (j = 0; j < 2; ++j) { tmp = x[i][j]; x[i][j] = x[1-i][1-j]; x[1-i][1-j] = tmp; } } } /* Update mask with function. */ for (i = 0; i < 16; ++i) { a = (i >> (2 * index + 0)) & 1; b = (i >> (2 * index + 1)) & 1; aset = (*mask >> i) & 1; bset = x[b][a]; if (func == FUNC_AND || func == FUNC_NAND) rset = aset & bset; else if (func == FUNC_OR || func == FUNC_NOR) rset = aset | bset; else if (func == FUNC_XOR || func == FUNC_NXOR) rset = aset ^ bset; if (func == FUNC_NAND || func == FUNC_NOR || func == FUNC_NXOR) rset = !rset; *mask &= ~(1 << i); if (rset) *mask |= 1 << i; } } /* * Build trigger LUTs used by 50 MHz and lower sample rates for supporting * simple pin change and state triggers. Only two transitions (rise/fall) can be * set at any time, but a full mask and value can be set (0/1). */ static int build_basic_trigger(struct triggerlut *lut, struct dev_context *devc) { int i,j; uint16_t masks[2] = { 0, 0 }; memset(lut, 0, sizeof(struct triggerlut)); /* Contant for simple triggers. */ lut->m4 = 0xa000; /* Value/mask trigger support. */ build_lut_entry(devc->trigger.simplevalue, devc->trigger.simplemask, lut->m2d); /* Rise/fall trigger support. */ for (i = 0, j = 0; i < 16; ++i) { if (devc->trigger.risingmask & (1 << i) || devc->trigger.fallingmask & (1 << i)) masks[j++] = 1 << i; } build_lut_entry(masks[0], masks[0], lut->m0d); build_lut_entry(masks[1], masks[1], lut->m1d); /* Add glue logic */ if (masks[0] || masks[1]) { /* Transition trigger. */ if (masks[0] & devc->trigger.risingmask) add_trigger_function(OP_RISE, FUNC_OR, 0, 0, &lut->m3); if (masks[0] & devc->trigger.fallingmask) add_trigger_function(OP_FALL, FUNC_OR, 0, 0, &lut->m3); if (masks[1] & devc->trigger.risingmask) add_trigger_function(OP_RISE, FUNC_OR, 1, 0, &lut->m3); if (masks[1] & devc->trigger.fallingmask) add_trigger_function(OP_FALL, FUNC_OR, 1, 0, &lut->m3); } else { /* Only value/mask trigger. */ lut->m3 = 0xffff; } /* Triggertype: event. */ lut->params.selres = 3; return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct clockselect_50 clockselect; int frac, triggerpin, ret; uint8_t triggerselect = 0; struct triggerinout triggerinout_conf; struct triggerlut lut; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; if (configure_channels(sdi) != SR_OK) { sr_err("Failed to configure channels."); return SR_ERR; } /* If the samplerate has not been set, default to 200 kHz. */ if (devc->cur_firmware == -1) { if ((ret = set_samplerate(sdi, SR_KHZ(200))) != SR_OK) return ret; } /* Enter trigger programming mode. */ sigma_set_register(WRITE_TRIGGER_SELECT1, 0x20, devc); /* 100 and 200 MHz mode. */ if (devc->cur_samplerate >= SR_MHZ(100)) { sigma_set_register(WRITE_TRIGGER_SELECT1, 0x81, devc); /* Find which pin to trigger on from mask. */ for (triggerpin = 0; triggerpin < 8; ++triggerpin) if ((devc->trigger.risingmask | devc->trigger.fallingmask) & (1 << triggerpin)) break; /* Set trigger pin and light LED on trigger. */ triggerselect = (1 << LEDSEL1) | (triggerpin & 0x7); /* Default rising edge. */ if (devc->trigger.fallingmask) triggerselect |= 1 << 3; /* All other modes. */ } else if (devc->cur_samplerate <= SR_MHZ(50)) { build_basic_trigger(&lut, devc); sigma_write_trigger_lut(&lut, devc); triggerselect = (1 << LEDSEL1) | (1 << LEDSEL0); } /* Setup trigger in and out pins to default values. */ memset(&triggerinout_conf, 0, sizeof(struct triggerinout)); triggerinout_conf.trgout_bytrigger = 1; triggerinout_conf.trgout_enable = 1; sigma_write_register(WRITE_TRIGGER_OPTION, (uint8_t *) &triggerinout_conf, sizeof(struct triggerinout), devc); /* Go back to normal mode. */ sigma_set_register(WRITE_TRIGGER_SELECT1, triggerselect, devc); /* Set clock select register. */ if (devc->cur_samplerate == SR_MHZ(200)) /* Enable 4 channels. */ sigma_set_register(WRITE_CLOCK_SELECT, 0xf0, devc); else if (devc->cur_samplerate == SR_MHZ(100)) /* Enable 8 channels. */ sigma_set_register(WRITE_CLOCK_SELECT, 0x00, devc); else { /* * 50 MHz mode (or fraction thereof). Any fraction down to * 50 MHz / 256 can be used, but is not supported by sigrok API. */ frac = SR_MHZ(50) / devc->cur_samplerate - 1; clockselect.async = 0; clockselect.fraction = frac; clockselect.disabled_channels = 0; sigma_write_register(WRITE_CLOCK_SELECT, (uint8_t *) &clockselect, sizeof(clockselect), devc); } /* Setup maximum post trigger time. */ sigma_set_register(WRITE_POST_TRIGGER, (devc->capture_ratio * 255) / 100, devc); /* Start acqusition. */ gettimeofday(&devc->start_tv, 0); sigma_set_register(WRITE_MODE, 0x0d, devc); devc->cb_data = cb_data; /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* Add capture source. */ sr_source_add(0, G_IO_IN, 10, receive_data, (void *)sdi); devc->state.state = SIGMA_CAPTURE; return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; (void)cb_data; devc = sdi->priv; devc->state.state = SIGMA_IDLE; sr_source_remove(0); return SR_OK; } SR_PRIV struct sr_dev_driver asix_sigma_driver_info = { .name = "asix-sigma", .longname = "ASIX SIGMA/SIGMA2", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = dev_clear, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/ikalogic-scanalogic2/0000755000175000017500000000000012332246734016250 500000000000000libsigrok-0.3.0/hardware/ikalogic-scanalogic2/protocol.h0000644000175000017500000001575212332246667020221 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Marc Schink * * 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 . */ #ifndef LIBSIGROK_HARDWARE_IKALOGIC_SCANALOGIC2_PROTOCOL_H #define LIBSIGROK_HARDWARE_IKALOGIC_SCANALOGIC2_PROTOCOL_H #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "ikalogic-scanalogic2" #define VENDOR_NAME "IKALOGIC" #define MODEL_NAME "Scanalogic-2" #define USB_VID_PID "20a0.4123" #define USB_INTERFACE 0 #define USB_TIMEOUT 5000 #define USB_REQUEST_TYPE_IN (LIBUSB_REQUEST_TYPE_CLASS | \ LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN) #define USB_REQUEST_TYPE_OUT (LIBUSB_REQUEST_TYPE_CLASS | \ LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT) #define USB_HID_GET_REPORT 0x01 #define USB_HID_SET_REPORT 0x09 #define USB_HID_REPORT_TYPE_FEATURE 0x300 #define NUM_SAMPLERATES 11 #define NUM_CHANNELS 4 #define TRIGGER_TYPES "rfc" /* * Number of sample bytes and samples the device can acquire. Note that the * vendor software can acquire 32736 sample bytes only but the device is capable * to acquire up to 32766 sample bytes. */ #define MAX_DEV_SAMPLE_BYTES 32766 #define MAX_DEV_SAMPLES (MAX_INT_SAMPLE_BYTES * 8) /* Number of sample bytes and samples the driver can acquire. */ #define MAX_SAMPLE_BYTES (MAX_DEV_SAMPLE_BYTES - 1) #define MAX_SAMPLES (MAX_SAMPLE_BYTES * 8) /* Maximum time that the trigger can be delayed in milliseconds. */ #define MAX_AFTER_TRIGGER_DELAY 65000 #define PACKET_LENGTH 128 /* Number of sample bytes per packet where a sample byte contains 8 samples. */ #define PACKET_NUM_SAMPLE_BYTES 124 /* Number of samples per packet. */ #define PACKET_NUM_SAMPLES (PACKET_NUM_SAMPLE_BYTES * 8) #define DEFAULT_SAMPLERATE SR_KHZ(1.25) /* * Time interval between the last status of available data received and the * moment when the next status request will be sent in microseconds. */ #define WAIT_DATA_READY_INTERVAL 1500000 #define CMD_SAMPLE 0x01 #define CMD_RESET 0x02 #define CMD_IDLE 0x07 #define CMD_INFO 0x0a #define TRIGGER_CHANNEL_ALL 0x00 #define TRIGGER_CHANNEL_0 0x01 #define TRIGGER_CHANNEL_1 0x02 #define TRIGGER_CHANNEL_2 0x03 #define TRIGGER_TYPE_NEGEDGE 0x00 #define TRIGGER_TYPE_POSEDGE 0x01 #define TRIGGER_TYPE_ANYEDGE 0x02 #define TRIGGER_TYPE_NONE 0x03 #define STATUS_DATA_READY 0x60 #define STATUS_WAITING_FOR_TRIGGER 0x61 #define STATUS_SAMPLING 0x62 #define STATUS_DEVICE_READY 0x63 struct device_info { /* Serial number of the device. */ uint32_t serial; /* Major version of the firmware. */ uint8_t fw_ver_major; /* Minor version of the firmware. */ uint8_t fw_ver_minor; }; enum { STATE_IDLE = 0, STATE_SAMPLE, STATE_WAIT_DATA_READY, STATE_RECEIVE_DATA, STATE_RESET_AND_IDLE, STATE_WAIT_DEVICE_READY }; /** Private, per-device-instance driver context. */ struct dev_context { /* Current selected samplerate. */ uint64_t samplerate; /* Device specific identifier for the current samplerate. */ uint8_t samplerate_id; /* Current sampling limit. */ uint64_t limit_samples; /* Calculated number of pre-trigger samples. */ uint64_t pre_trigger_samples; /* Number of pre- and post-trigger sample bytes to acquire. */ uint16_t pre_trigger_bytes; uint16_t post_trigger_bytes; /* Device specific settings for the trigger. */ uint8_t trigger_channel; uint8_t trigger_type; unsigned int capture_ratio; /* Time that the trigger will be delayed in milliseconds. */ uint16_t after_trigger_delay; void *cb_data; /* Array to provide an index based access to all channels. */ const struct sr_channel *channels[NUM_CHANNELS]; struct libusb_transfer *xfer_in, *xfer_out; /* * Buffer to store setup and payload data for incoming and outgoing * transfers. */ uint8_t xfer_buf_in[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH]; uint8_t xfer_buf_out[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH]; /* Pointers to the payload of incoming and outgoing transfers. */ uint8_t *xfer_data_in, *xfer_data_out; /* Current state of the state machine */ unsigned int state; /* Next state of the state machine. */ unsigned int next_state; /* * Locking variable to ensure that no status about available data will * be requested until the last status was received. */ gboolean wait_data_ready_locked; /* * Time when the last response about the status of available data was * received. */ int64_t wait_data_ready_time; /* * Indicates that stopping of the acquisition is currently in progress. */ gboolean stopping_in_progress; /* * Buffer which contains the samples received from the device for each * channel except the last one. The samples of the last channel will be * processed directly after they will be received. */ uint8_t sample_buffer[NUM_CHANNELS - 1][MAX_DEV_SAMPLE_BYTES]; /* Expected number of sample packets for each channel. */ uint16_t num_sample_packets; /* Number of samples already processed. */ uint64_t samples_processed; /* Sample packet number that is currently processed. */ uint16_t sample_packet; /* Channel number that is currently processed. */ uint8_t channel; /* Number of enabled channels. */ unsigned int num_enabled_channels; /* Array to provide a sequential access to all enabled channel indices. */ uint8_t channel_map[NUM_CHANNELS]; /* Indicates whether a transfer failed. */ gboolean transfer_error; }; SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data); SR_PRIV void sl2_receive_transfer_in(struct libusb_transfer *transfer); SR_PRIV void sl2_receive_transfer_out(struct libusb_transfer *transfer); SR_PRIV int sl2_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate); SR_PRIV int sl2_set_limit_samples(const struct sr_dev_inst *sdi, uint64_t limit_samples); SR_PRIV void sl2_configure_trigger(const struct sr_dev_inst *sdi); SR_PRIV int sl2_set_capture_ratio(const struct sr_dev_inst *sdi, uint64_t capture_ratio); SR_PRIV int sl2_set_after_trigger_delay(const struct sr_dev_inst *sdi, uint64_t after_trigger_delay); SR_PRIV void sl2_calculate_trigger_samples(const struct sr_dev_inst *sdi); SR_PRIV int sl2_get_device_info(struct sr_usb_dev_inst usb, struct device_info *dev_info); SR_PRIV int sl2_transfer_in(libusb_device_handle *dev_handle, uint8_t *data); SR_PRIV int sl2_transfer_out(libusb_device_handle *dev_handle, uint8_t *data); #endif libsigrok-0.3.0/hardware/ikalogic-scanalogic2/protocol.c0000644000175000017500000004727512332246667020221 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Marc Schink * * 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 . */ #include "protocol.h" extern struct sr_dev_driver ikalogic_scanalogic2_driver_info; static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info; extern uint64_t sl2_samplerates[NUM_SAMPLERATES]; static void stop_acquisition(struct sr_dev_inst *sdi) { struct drv_context *drvc = sdi->driver->priv; struct dev_context *devc; struct sr_datafeed_packet packet; devc = sdi->priv; /* Remove USB file descriptors from polling. */ usb_source_remove(drvc->sr_ctx); packet.type = SR_DF_END; sr_session_send(devc->cb_data, &packet); sdi->status = SR_ST_ACTIVE; } static void abort_acquisition(struct sr_dev_inst *sdi) { struct drv_context *drvc = sdi->driver->priv; struct dev_context *devc; struct sr_datafeed_packet packet; devc = sdi->priv; /* Remove USB file descriptors from polling. */ usb_source_remove(drvc->sr_ctx); packet.type = SR_DF_END; sr_session_send(devc->cb_data, &packet); sdi->driver->dev_close(sdi); } static void buffer_sample_data(const struct sr_dev_inst *sdi) { struct dev_context *devc; unsigned int offset, packet_length; devc = sdi->priv; if (devc->channels[devc->channel]->enabled) { offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES; /* * Determine the packet length to ensure that the last packet * will not exceed the buffer size. */ packet_length = MIN(PACKET_NUM_SAMPLE_BYTES, MAX_DEV_SAMPLE_BYTES - offset); /* * Skip the first 4 bytes of the source buffer because they * contain channel and packet information only. */ memcpy(devc->sample_buffer[devc->channel] + offset, devc->xfer_data_in + 4, packet_length); } } static void process_sample_data(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; uint8_t i, j, tmp, buffer[PACKET_NUM_SAMPLES], *ptr[NUM_CHANNELS]; uint16_t offset, n = 0; int8_t k; devc = sdi->priv; offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES; /* * Array of pointers to the sample data of all channels up to the last * enabled one for an uniform access to them. Note that the currently * received samples always belong to the last enabled channel. */ for (i = 0; i < devc->num_enabled_channels - 1; i++) ptr[i] = devc->sample_buffer[devc->channel_map[i]] + offset; /* * Skip the first 4 bytes of the buffer because they contain channel * and packet information only. */ ptr[i] = devc->xfer_data_in + 4; for (i = 0; i < PACKET_NUM_SAMPLE_BYTES; i++) { /* Stop processing if all requested samples are processed. */ if (devc->samples_processed == devc->limit_samples) break; k = 7; if (devc->samples_processed == 0) { /* * Adjust the position of the first sample to be * processed because possibly more samples than * necessary might have been acquired. This is because * the number of acquired samples is always rounded up * to a multiple of 8. */ k = k - (devc->pre_trigger_bytes * 8) + devc->pre_trigger_samples; sr_dbg("Start processing at sample: %d.", 7 - k); /* * Send the trigger before the first sample is * processed if no pre trigger samples were calculated * through the capture ratio. */ if (devc->trigger_type != TRIGGER_TYPE_NONE && devc->pre_trigger_samples == 0) { packet.type = SR_DF_TRIGGER; sr_session_send(devc->cb_data, &packet); } } for (; k >= 0; k--) { /* * Stop processing if all requested samples are * processed. */ if (devc->samples_processed == devc->limit_samples) break; buffer[n] = 0; /* * Extract the current sample for each enabled channel * and store them in the buffer. */ for (j = 0; j < devc->num_enabled_channels; j++) { tmp = (ptr[j][i] & (1 << k)) >> k; buffer[n] |= tmp << devc->channel_map[j]; } n++; devc->samples_processed++; /* * Send all processed samples and the trigger if the * number of processed samples reaches the calculated * number of pre trigger samples. */ if (devc->samples_processed == devc->pre_trigger_samples && devc->trigger_type != TRIGGER_TYPE_NONE) { packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = n; logic.unitsize = 1; logic.data = buffer; sr_session_send(devc->cb_data, &packet); packet.type = SR_DF_TRIGGER; sr_session_send(devc->cb_data, &packet); n = 0; } } } if (n > 0) { packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = n; logic.unitsize = 1; logic.data = buffer; sr_session_send(devc->cb_data, &packet); } } SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; struct drv_context *drvc; struct timeval tv; int64_t current_time, time_elapsed; int ret = 0; (void)fd; (void)revents; if (!(sdi = cb_data)) return TRUE; if (!(devc = sdi->priv)) return TRUE; drvc = di->priv; current_time = g_get_monotonic_time(); if (devc->state == STATE_WAIT_DATA_READY && !devc->wait_data_ready_locked) { time_elapsed = current_time - devc->wait_data_ready_time; /* * Check here for stopping in addition to the transfer * callback functions to avoid waiting until the * WAIT_DATA_READY_INTERVAL has expired. */ if (sdi->status == SR_ST_STOPPING) { if (!devc->stopping_in_progress) { devc->next_state = STATE_RESET_AND_IDLE; devc->stopping_in_progress = TRUE; ret = libusb_submit_transfer(devc->xfer_in); } } else if (time_elapsed >= WAIT_DATA_READY_INTERVAL) { devc->wait_data_ready_locked = TRUE; ret = libusb_submit_transfer(devc->xfer_in); } } if (ret != 0) { sr_err("Submit transfer failed: %s.", libusb_error_name(ret)); abort_acquisition(sdi); return TRUE; } tv.tv_sec = 0; tv.tv_usec = 0; libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, NULL); /* Check if an error occurred on a transfer. */ if (devc->transfer_error) abort_acquisition(sdi); return TRUE; } SR_PRIV void sl2_receive_transfer_in( struct libusb_transfer *transfer) { struct sr_dev_inst *sdi; struct dev_context *devc; uint8_t last_channel; int ret = 0; sdi = transfer->user_data; devc = sdi->priv; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { sr_err("Transfer to device failed: %i.", transfer->status); devc->transfer_error = TRUE; return; } if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) { devc->next_state = STATE_RESET_AND_IDLE; devc->stopping_in_progress = TRUE; if (libusb_submit_transfer(devc->xfer_in) != 0) { sr_err("Submit transfer failed: %s.", libusb_error_name(ret)); devc->transfer_error = TRUE; } return; } if (devc->state != devc->next_state) sr_spew("State changed from %i to %i.", devc->state, devc->next_state); devc->state = devc->next_state; if (devc->state == STATE_WAIT_DATA_READY) { /* Check if the received data are a valid device status. */ if (devc->xfer_data_in[0] == 0x05) { if (devc->xfer_data_in[1] == STATUS_WAITING_FOR_TRIGGER) sr_dbg("Waiting for trigger."); else if (devc->xfer_data_in[1] == STATUS_SAMPLING) sr_dbg("Sampling in progress."); } /* * Check if the received data are a valid device status and the * sample data are ready. */ if (devc->xfer_data_in[0] == 0x05 && devc->xfer_data_in[1] == STATUS_DATA_READY) { devc->next_state = STATE_RECEIVE_DATA; ret = libusb_submit_transfer(transfer); } else { devc->wait_data_ready_locked = FALSE; devc->wait_data_ready_time = g_get_monotonic_time(); } } else if (devc->state == STATE_RECEIVE_DATA) { last_channel = devc->channel_map[devc->num_enabled_channels - 1]; if (devc->channel < last_channel) { buffer_sample_data(sdi); } else if (devc->channel == last_channel) { process_sample_data(sdi); } else { /* * Stop acquisition because all samples of enabled * channels are processed. */ devc->next_state = STATE_RESET_AND_IDLE; } devc->sample_packet++; devc->sample_packet %= devc->num_sample_packets; if (devc->sample_packet == 0) devc->channel++; ret = libusb_submit_transfer(transfer); } else if (devc->state == STATE_RESET_AND_IDLE) { /* Check if the received data are a valid device status. */ if (devc->xfer_data_in[0] == 0x05) { if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) { devc->next_state = STATE_IDLE; devc->xfer_data_out[0] = CMD_IDLE; } else { devc->next_state = STATE_WAIT_DEVICE_READY; devc->xfer_data_out[0] = CMD_RESET; } ret = libusb_submit_transfer(devc->xfer_out); } else { /* * The received device status is invalid which * indicates that the device is not ready to accept * commands. Request a new device status until a valid * device status is received. */ ret = libusb_submit_transfer(transfer); } } else if (devc->state == STATE_WAIT_DEVICE_READY) { /* Check if the received data are a valid device status. */ if (devc->xfer_data_in[0] == 0x05) { if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) { devc->next_state = STATE_IDLE; devc->xfer_data_out[0] = CMD_IDLE; } else { /* * The received device status is valid but the * device is not ready. Probably the device did * not recognize the last reset. Reset the * device again. */ devc->xfer_data_out[0] = CMD_RESET; } ret = libusb_submit_transfer(devc->xfer_out); } else { /* * The device is not ready and therefore not able to * change to the idle state. Request a new device * status until the device is ready. */ ret = libusb_submit_transfer(transfer); } } if (ret != 0) { sr_err("Submit transfer failed: %s.", libusb_error_name(ret)); devc->transfer_error = TRUE; } } SR_PRIV void sl2_receive_transfer_out( struct libusb_transfer *transfer) { struct sr_dev_inst *sdi; struct dev_context *devc; int ret = 0; sdi = transfer->user_data; devc = sdi->priv; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { sr_err("Transfer to device failed: %i.", transfer->status); devc->transfer_error = TRUE; return; } if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) { devc->next_state = STATE_RESET_AND_IDLE; devc->stopping_in_progress = TRUE; if (libusb_submit_transfer(devc->xfer_in) != 0) { sr_err("Submit transfer failed: %s.", libusb_error_name(ret)); devc->transfer_error = TRUE; } return; } if (devc->state != devc->next_state) sr_spew("State changed from %i to %i.", devc->state, devc->next_state); devc->state = devc->next_state; if (devc->state == STATE_IDLE) { stop_acquisition(sdi); } else if (devc->state == STATE_SAMPLE) { devc->next_state = STATE_WAIT_DATA_READY; ret = libusb_submit_transfer(devc->xfer_in); } else if (devc->state == STATE_WAIT_DEVICE_READY) { ret = libusb_submit_transfer(devc->xfer_in); } if (ret != 0) { sr_err("Submit transfer failed: %s.", libusb_error_name(ret)); devc->transfer_error = TRUE; } } SR_PRIV int sl2_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate) { struct dev_context *devc; unsigned int i; devc = sdi->priv; for (i = 0; i < NUM_SAMPLERATES; i++) { if (sl2_samplerates[i] == samplerate) { devc->samplerate = samplerate; devc->samplerate_id = NUM_SAMPLERATES - i - 1; return SR_OK; } } return SR_ERR_ARG; } SR_PRIV int sl2_set_limit_samples(const struct sr_dev_inst *sdi, uint64_t limit_samples) { struct dev_context *devc; devc = sdi->priv; if (limit_samples == 0) { sr_err("Invalid number of limit samples: %" PRIu64 ".", limit_samples); return SR_ERR_ARG; } if (limit_samples > MAX_SAMPLES) limit_samples = MAX_SAMPLES; sr_dbg("Limit samples set to %" PRIu64 ".", limit_samples); devc->limit_samples = limit_samples; return SR_OK; } SR_PRIV void sl2_configure_trigger(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_channel *ch; uint8_t trigger_type; int channel_index, num_triggers_anyedge; char *trigger; GSList *l; devc = sdi->priv; /* Disable the trigger by default. */ devc->trigger_channel = TRIGGER_CHANNEL_0; devc->trigger_type = TRIGGER_TYPE_NONE; num_triggers_anyedge = 0; for (l = sdi->channels, channel_index = 0; l; l = l->next, channel_index++) { ch = l->data; trigger = ch->trigger; if (!trigger || !ch->enabled) continue; switch (*trigger) { case 'r': trigger_type = TRIGGER_TYPE_POSEDGE; break; case 'f': trigger_type = TRIGGER_TYPE_NEGEDGE; break; case 'c': trigger_type = TRIGGER_TYPE_ANYEDGE; num_triggers_anyedge++; break; default: continue; } devc->trigger_channel = channel_index + 1; devc->trigger_type = trigger_type; } /* * Set trigger to any edge on all channels if the trigger for each * channel is set to any edge. */ if (num_triggers_anyedge == NUM_CHANNELS) { devc->trigger_channel = TRIGGER_CHANNEL_ALL; devc->trigger_type = TRIGGER_TYPE_ANYEDGE; } sr_dbg("Trigger set to channel 0x%02x and type 0x%02x.", devc->trigger_channel, devc->trigger_type); } SR_PRIV int sl2_set_capture_ratio(const struct sr_dev_inst *sdi, uint64_t capture_ratio) { struct dev_context *devc; devc = sdi->priv; if (capture_ratio > 100) { sr_err("Invalid capture ratio: %" PRIu64 " %%.", capture_ratio); return SR_ERR_ARG; } sr_info("Capture ratio set to %" PRIu64 " %%.", capture_ratio); devc->capture_ratio = capture_ratio; return SR_OK; } SR_PRIV int sl2_set_after_trigger_delay(const struct sr_dev_inst *sdi, uint64_t after_trigger_delay) { struct dev_context *devc; devc = sdi->priv; if (after_trigger_delay > MAX_AFTER_TRIGGER_DELAY) { sr_err("Invalid after trigger delay: %" PRIu64 " ms.", after_trigger_delay); return SR_ERR_ARG; } sr_info("After trigger delay set to %" PRIu64 " ms.", after_trigger_delay); devc->after_trigger_delay = after_trigger_delay; return SR_OK; } SR_PRIV void sl2_calculate_trigger_samples(const struct sr_dev_inst *sdi) { struct dev_context *devc; uint64_t pre_trigger_samples, post_trigger_samples; uint16_t pre_trigger_bytes, post_trigger_bytes; uint8_t cr; devc = sdi->priv; cr = devc->capture_ratio; /* Ignore the capture ratio if no trigger is enabled. */ if (devc->trigger_type == TRIGGER_TYPE_NONE) cr = 0; pre_trigger_samples = (devc->limit_samples * cr) / 100; post_trigger_samples = (devc->limit_samples * (100 - cr)) / 100; /* * Increase the number of post trigger samples by one to compensate the * possible loss of a sample through integer rounding. */ if (pre_trigger_samples + post_trigger_samples != devc->limit_samples) post_trigger_samples++; /* * The device requires the number of samples in multiples of 8 which * will also be called sample bytes in the following. */ pre_trigger_bytes = pre_trigger_samples / 8; post_trigger_bytes = post_trigger_samples / 8; /* * Round up the number of sample bytes to ensure that at least the * requested number of samples will be acquired. Note that due to this * rounding the buffer to store these sample bytes needs to be at least * one sample byte larger than the minimal number of sample bytes * needed to store the requested samples. */ if (pre_trigger_samples % 8 != 0) pre_trigger_bytes++; if (post_trigger_samples % 8 != 0) post_trigger_bytes++; sr_info("Pre trigger samples: %" PRIu64 ".", pre_trigger_samples); sr_info("Post trigger samples: %" PRIu64 ".", post_trigger_samples); sr_dbg("Pre trigger sample bytes: %" PRIu16 ".", pre_trigger_bytes); sr_dbg("Post trigger sample bytes: %" PRIu16 ".", post_trigger_bytes); devc->pre_trigger_samples = pre_trigger_samples; devc->pre_trigger_bytes = pre_trigger_bytes; devc->post_trigger_bytes = post_trigger_bytes; } SR_PRIV int sl2_get_device_info(struct sr_usb_dev_inst usb, struct device_info *dev_info) { struct drv_context *drvc; uint8_t buffer[PACKET_LENGTH]; int ret; drvc = di->priv; if (!dev_info) return SR_ERR_ARG; if (sr_usb_open(drvc->sr_ctx->libusb_ctx, &usb) != SR_OK) return SR_ERR; /* * Determine if a kernel driver is active on this interface and, if so, * detach it. */ if (libusb_kernel_driver_active(usb.devhdl, USB_INTERFACE) == 1) { ret = libusb_detach_kernel_driver(usb.devhdl, USB_INTERFACE); if (ret < 0) { sr_err("Failed to detach kernel driver: %s.", libusb_error_name(ret)); libusb_close(usb.devhdl); return SR_ERR; } } ret = libusb_claim_interface(usb.devhdl, USB_INTERFACE); if (ret) { sr_err("Failed to claim interface: %s.", libusb_error_name(ret)); libusb_close(usb.devhdl); return SR_ERR; } memset(buffer, 0, sizeof(buffer)); /* * Reset the device to ensure it is in a proper state to request the * device information. */ buffer[0] = CMD_RESET; if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) { sr_err("Resetting of device failed: %s.", libusb_error_name(ret)); libusb_release_interface(usb.devhdl, USB_INTERFACE); libusb_close(usb.devhdl); return SR_ERR; } buffer[0] = CMD_INFO; if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) { sr_err("Requesting of device information failed: %s.", libusb_error_name(ret)); libusb_release_interface(usb.devhdl, USB_INTERFACE); libusb_close(usb.devhdl); return SR_ERR; } if ((ret = sl2_transfer_in(usb.devhdl, buffer)) != PACKET_LENGTH) { sr_err("Receiving of device information failed: %s.", libusb_error_name(ret)); libusb_release_interface(usb.devhdl, USB_INTERFACE); libusb_close(usb.devhdl); return SR_ERR; } memcpy(&(dev_info->serial), buffer + 1, sizeof(uint32_t)); dev_info->serial = GUINT32_FROM_LE(dev_info->serial); dev_info->fw_ver_major = buffer[5]; dev_info->fw_ver_minor = buffer[6]; buffer[0] = CMD_RESET; if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) { sr_err("Device reset failed: %s.", libusb_error_name(ret)); libusb_release_interface(usb.devhdl, USB_INTERFACE); libusb_close(usb.devhdl); return SR_ERR; } /* * Set the device to idle state. If the device is not in idle state it * possibly will reset itself after a few seconds without being used * and thereby close the connection. */ buffer[0] = CMD_IDLE; if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) { sr_err("Failed to set device in idle state: %s.", libusb_error_name(ret)); libusb_release_interface(usb.devhdl, USB_INTERFACE); libusb_close(usb.devhdl); return SR_ERR; } ret = libusb_release_interface(usb.devhdl, USB_INTERFACE); if (ret < 0) { sr_err("Failed to release interface: %s.", libusb_error_name(ret)); libusb_close(usb.devhdl); return SR_ERR; } libusb_close(usb.devhdl); return SR_OK; } SR_PRIV int sl2_transfer_in(libusb_device_handle *dev_handle, uint8_t *data) { return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_IN, USB_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, (unsigned char *)data, PACKET_LENGTH, USB_TIMEOUT); } SR_PRIV int sl2_transfer_out(libusb_device_handle *dev_handle, uint8_t *data) { return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_OUT, USB_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, (unsigned char *)data, PACKET_LENGTH, USB_TIMEOUT); } libsigrok-0.3.0/hardware/ikalogic-scanalogic2/api.c0000644000175000017500000003053212332246667017115 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Marc Schink * * 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 . */ #include "protocol.h" static const int hwcaps[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_SAMPLERATE, SR_CONF_LIMIT_SAMPLES, SR_CONF_TRIGGER_TYPE, SR_CONF_CAPTURE_RATIO, }; SR_PRIV const uint64_t sl2_samplerates[NUM_SAMPLERATES] = { SR_KHZ(1.25), SR_KHZ(10), SR_KHZ(50), SR_KHZ(100), SR_KHZ(250), SR_KHZ(500), SR_MHZ(1), SR_MHZ(2.5), SR_MHZ(5), SR_MHZ(10), SR_MHZ(20), }; static const char *channel_names[NUM_CHANNELS + 1] = { "0", "1", "2", "3", NULL, }; SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info; static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { GSList *usb_devices, *devices, *l; struct drv_context *drvc; struct sr_dev_inst *sdi; struct sr_channel *ch; struct dev_context *devc; struct sr_usb_dev_inst *usb; struct device_info dev_info; int ret, device_index, i; char *fw_ver_str; (void)options; devices = NULL; drvc = di->priv; drvc->instances = NULL; device_index = 0; usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_VID_PID); if (usb_devices == NULL) return NULL; for (l = usb_devices; l; l = l->next) { usb = l->data; if ((ret = sl2_get_device_info(*usb, &dev_info)) < 0) { sr_warn("Failed to get device information: %d.", ret); sr_usb_dev_inst_free(usb); continue; } if (!(devc = g_try_malloc(sizeof(struct dev_context)))) { sr_err("Device instance malloc failed."); sr_usb_dev_inst_free(usb); continue; } if (!(devc->xfer_in = libusb_alloc_transfer(0))) { sr_err("Transfer malloc failed."); sr_usb_dev_inst_free(usb); g_free(devc); continue; } if (!(devc->xfer_out = libusb_alloc_transfer(0))) { sr_err("Transfer malloc failed."); sr_usb_dev_inst_free(usb); libusb_free_transfer(devc->xfer_in); g_free(devc); continue; } fw_ver_str = g_strdup_printf("%u.%u", dev_info.fw_ver_major, dev_info.fw_ver_minor); if (!fw_ver_str) { sr_err("Firmware string malloc failed."); sr_usb_dev_inst_free(usb); libusb_free_transfer(devc->xfer_in); libusb_free_transfer(devc->xfer_out); g_free(devc); continue; } sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE, VENDOR_NAME, MODEL_NAME, fw_ver_str); g_free(fw_ver_str); if (!sdi) { sr_err("sr_dev_inst_new failed."); sr_usb_dev_inst_free(usb); libusb_free_transfer(devc->xfer_in); libusb_free_transfer(devc->xfer_out); g_free(devc); continue; } sdi->priv = devc; sdi->driver = di; sdi->inst_type = SR_INST_USB; sdi->conn = usb; for (i = 0; channel_names[i]; i++) { ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]); sdi->channels = g_slist_append(sdi->channels, ch); devc->channels[i] = ch; } devc->state = STATE_IDLE; devc->next_state = STATE_IDLE; /* Set default samplerate. */ sl2_set_samplerate(sdi, DEFAULT_SAMPLERATE); /* Set default capture ratio. */ devc->capture_ratio = 0; /* Set default after trigger delay. */ devc->after_trigger_delay = 0; memset(devc->xfer_buf_in, 0, LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH); memset(devc->xfer_buf_out, 0, LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH); libusb_fill_control_setup(devc->xfer_buf_in, USB_REQUEST_TYPE_IN, USB_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, PACKET_LENGTH); libusb_fill_control_setup(devc->xfer_buf_out, USB_REQUEST_TYPE_OUT, USB_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, PACKET_LENGTH); devc->xfer_data_in = devc->xfer_buf_in + LIBUSB_CONTROL_SETUP_SIZE; devc->xfer_data_out = devc->xfer_buf_out + LIBUSB_CONTROL_SETUP_SIZE; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); device_index++; } g_slist_free(usb_devices); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static void clear_dev_context(void *priv) { struct dev_context *devc; devc = priv; sr_dbg("Device context cleared."); libusb_free_transfer(devc->xfer_in); libusb_free_transfer(devc->xfer_out); g_free(devc); } static int dev_clear(void) { return std_dev_clear(di, &clear_dev_context); } static int dev_open(struct sr_dev_inst *sdi) { struct drv_context *drvc; struct dev_context *devc; struct sr_usb_dev_inst *usb; uint8_t buffer[PACKET_LENGTH]; int ret; if (!(drvc = di->priv)) { sr_err("Driver was not initialized."); return SR_ERR; } usb = sdi->conn; devc = sdi->priv; if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK) return SR_ERR; /* * Determine if a kernel driver is active on this interface and, if so, * detach it. */ if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) { ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE); if (ret < 0) { sr_err("Failed to detach kernel driver: %s.", libusb_error_name(ret)); return SR_ERR; } } if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE)) < 0) { sr_err("Failed to claim interface: %s.", libusb_error_name(ret)); return SR_ERR; } libusb_fill_control_transfer(devc->xfer_in, usb->devhdl, devc->xfer_buf_in, sl2_receive_transfer_in, sdi, USB_TIMEOUT); libusb_fill_control_transfer(devc->xfer_out, usb->devhdl, devc->xfer_buf_out, sl2_receive_transfer_out, sdi, USB_TIMEOUT); memset(buffer, 0, sizeof(buffer)); buffer[0] = CMD_RESET; if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) { sr_err("Device reset failed: %s.", libusb_error_name(ret)); return SR_ERR; } /* * Set the device to idle state. If the device is not in idle state it * possibly will reset itself after a few seconds without being used * and thereby close the connection. */ buffer[0] = CMD_IDLE; if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) { sr_err("Failed to set device in idle state: %s.", libusb_error_name(ret)); return SR_ERR; } sdi->status = SR_ST_ACTIVE; return SR_OK; } static int dev_close(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; if (!di->priv) { sr_err("Driver was not initialized."); return SR_ERR; } usb = sdi->conn; if (!usb->devhdl) return SR_OK; libusb_release_interface(usb->devhdl, USB_INTERFACE); libusb_close(usb->devhdl); usb->devhdl = NULL; sdi->status = SR_ST_INACTIVE; return SR_OK; } static int cleanup(void) { return dev_clear(); } static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; int ret; (void)cg; ret = SR_OK; devc = sdi->priv; switch (key) { case SR_CONF_SAMPLERATE: *data = g_variant_new_uint64(devc->samplerate); break; case SR_CONF_CAPTURE_RATIO: *data = g_variant_new_uint64(devc->capture_ratio); break; default: return SR_ERR_NA; } return ret; } static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { uint64_t samplerate, limit_samples, capture_ratio; int ret; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; ret = SR_OK; switch (key) { case SR_CONF_LIMIT_SAMPLES: limit_samples = g_variant_get_uint64(data); ret = sl2_set_limit_samples(sdi, limit_samples); break; case SR_CONF_SAMPLERATE: samplerate = g_variant_get_uint64(data); ret = sl2_set_samplerate(sdi, samplerate); break; case SR_CONF_CAPTURE_RATIO: capture_ratio = g_variant_get_uint64(data); ret = sl2_set_capture_ratio(sdi, capture_ratio); break; default: return SR_ERR_NA; } return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { GVariant *gvar, *grange[2]; GVariantBuilder gvb; int ret; (void)sdi; (void)cg; ret = SR_OK; switch (key) { case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; case SR_CONF_SAMPLERATE: g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), sl2_samplerates, ARRAY_SIZE(sl2_samplerates), sizeof(uint64_t)); g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; case SR_CONF_TRIGGER_TYPE: *data = g_variant_new_string(TRIGGER_TYPES); break; case SR_CONF_LIMIT_SAMPLES: grange[0] = g_variant_new_uint64(0); grange[1] = g_variant_new_uint64(MAX_SAMPLES); *data = g_variant_new_tuple(grange, 2); break; default: return SR_ERR_NA; } return ret; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct drv_context *drvc; struct dev_context *devc; uint16_t trigger_bytes, tmp; unsigned int i, j; int ret; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; drvc = di->priv; devc->cb_data = cb_data; devc->wait_data_ready_locked = TRUE; devc->stopping_in_progress = FALSE; devc->transfer_error = FALSE; devc->samples_processed = 0; devc->channel = 0; devc->sample_packet = 0; /* * The trigger must be configured first because the calculation of the * pre and post trigger samples depends on a configured trigger. */ sl2_configure_trigger(sdi); sl2_calculate_trigger_samples(sdi); trigger_bytes = devc->pre_trigger_bytes + devc->post_trigger_bytes; /* Calculate the number of expected sample packets. */ devc->num_sample_packets = trigger_bytes / PACKET_NUM_SAMPLE_BYTES; /* Round up the number of expected sample packets. */ if (trigger_bytes % PACKET_NUM_SAMPLE_BYTES != 0) devc->num_sample_packets++; devc->num_enabled_channels = 0; /* * Count the number of enabled channels and number them for a sequential * access. */ for (i = 0, j = 0; i < NUM_CHANNELS; i++) { if (devc->channels[i]->enabled) { devc->num_enabled_channels++; devc->channel_map[j] = i; j++; } } sr_dbg("Number of enabled channels: %i.", devc->num_enabled_channels); /* Set up the transfer buffer for the acquisition. */ devc->xfer_data_out[0] = CMD_SAMPLE; devc->xfer_data_out[1] = 0x00; tmp = GUINT16_TO_LE(devc->pre_trigger_bytes); memcpy(devc->xfer_data_out + 2, &tmp, sizeof(tmp)); tmp = GUINT16_TO_LE(devc->post_trigger_bytes); memcpy(devc->xfer_data_out + 4, &tmp, sizeof(tmp)); devc->xfer_data_out[6] = devc->samplerate_id; devc->xfer_data_out[7] = devc->trigger_type; devc->xfer_data_out[8] = devc->trigger_channel; devc->xfer_data_out[9] = 0x00; tmp = GUINT16_TO_LE(devc->after_trigger_delay); memcpy(devc->xfer_data_out + 10, &tmp, sizeof(tmp)); if ((ret = libusb_submit_transfer(devc->xfer_out)) != 0) { sr_err("Submit transfer failed: %s.", libusb_error_name(ret)); return SR_ERR; } usb_source_add(drvc->sr_ctx, 100, ikalogic_scanalogic2_receive_data, (void *)sdi); sr_dbg("Acquisition started successfully."); /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); devc->next_state = STATE_SAMPLE; return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; sr_dbg("Stopping acquisition."); sdi->status = SR_ST_STOPPING; return SR_OK; } SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info = { .name = "ikalogic-scanalogic2", .longname = "IKALOGIC Scanalogic-2", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = dev_clear, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/fluke-dmm/0000755000175000017500000000000012332246734014164 500000000000000libsigrok-0.3.0/hardware/fluke-dmm/fluke.c0000644000175000017500000003503012332246667015364 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "fluke-dmm.h" static struct sr_datafeed_analog *handle_qm_18x(const struct sr_dev_inst *sdi, char **tokens) { struct sr_datafeed_analog *analog; float fvalue; char *e, *u; gboolean is_oor; if (strcmp(tokens[0], "QM") || !tokens[1]) return NULL; if ((e = strstr(tokens[1], "Out of range"))) { is_oor = TRUE; fvalue = -1; while(*e && *e != '.') e++; } else { is_oor = FALSE; /* Delimit the float, since sr_atof_ascii() wants only * a valid float here. */ e = tokens[1]; while(*e && *e != ' ') e++; *e++ = '\0'; if (sr_atof_ascii(tokens[1], &fvalue) != SR_OK || fvalue == 0.0) { /* Happens all the time, when switching modes. */ sr_dbg("Invalid float."); return NULL; } } while(*e && *e == ' ') e++; if (!(analog = g_try_malloc0(sizeof(struct sr_datafeed_analog)))) return NULL; if (!(analog->data = g_try_malloc(sizeof(float)))) return NULL; analog->channels = sdi->channels; analog->num_samples = 1; if (is_oor) *analog->data = NAN; else *analog->data = fvalue; analog->mq = -1; if ((u = strstr(e, "V DC")) || (u = strstr(e, "V AC"))) { analog->mq = SR_MQ_VOLTAGE; analog->unit = SR_UNIT_VOLT; if (!is_oor && e[0] == 'm') *analog->data /= 1000; /* This catches "V AC", "V DC" and "V AC+DC". */ if (strstr(u, "AC")) analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS; if (strstr(u, "DC")) analog->mqflags |= SR_MQFLAG_DC; } else if ((u = strstr(e, "dBV")) || (u = strstr(e, "dBm"))) { analog->mq = SR_MQ_VOLTAGE; if (u[2] == 'm') analog->unit = SR_UNIT_DECIBEL_MW; else analog->unit = SR_UNIT_DECIBEL_VOLT; analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS; } else if ((u = strstr(e, "Ohms"))) { analog->mq = SR_MQ_RESISTANCE; analog->unit = SR_UNIT_OHM; if (is_oor) *analog->data = INFINITY; else if (e[0] == 'k') *analog->data *= 1000; else if (e[0] == 'M') *analog->data *= 1000000; } else if (!strcmp(e, "nS")) { analog->mq = SR_MQ_CONDUCTANCE; analog->unit = SR_UNIT_SIEMENS; *analog->data /= 1e+9; } else if ((u = strstr(e, "Farads"))) { analog->mq = SR_MQ_CAPACITANCE; analog->unit = SR_UNIT_FARAD; if (!is_oor) { if (e[0] == 'm') *analog->data /= 1e+3; else if (e[0] == 'u') *analog->data /= 1e+6; else if (e[0] == 'n') *analog->data /= 1e+9; } } else if ((u = strstr(e, "Deg C")) || (u = strstr(e, "Deg F"))) { analog->mq = SR_MQ_TEMPERATURE; if (u[4] == 'C') analog->unit = SR_UNIT_CELSIUS; else analog->unit = SR_UNIT_FAHRENHEIT; } else if ((u = strstr(e, "A AC")) || (u = strstr(e, "A DC"))) { analog->mq = SR_MQ_CURRENT; analog->unit = SR_UNIT_AMPERE; /* This catches "A AC", "A DC" and "A AC+DC". */ if (strstr(u, "AC")) analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS; if (strstr(u, "DC")) analog->mqflags |= SR_MQFLAG_DC; if (!is_oor) { if (e[0] == 'm') *analog->data /= 1e+3; else if (e[0] == 'u') *analog->data /= 1e+6; } } else if ((u = strstr(e, "Hz"))) { analog->mq = SR_MQ_FREQUENCY; analog->unit = SR_UNIT_HERTZ; if (e[0] == 'k') *analog->data *= 1e+3; } else if (!strcmp(e, "%")) { analog->mq = SR_MQ_DUTY_CYCLE; analog->unit = SR_UNIT_PERCENTAGE; } else if ((u = strstr(e, "ms"))) { analog->mq = SR_MQ_PULSE_WIDTH; analog->unit = SR_UNIT_SECOND; *analog->data /= 1e+3; } if (analog->mq == -1) { /* Not a valid measurement. */ g_free(analog->data); g_free(analog); analog = NULL; } return analog; } static struct sr_datafeed_analog *handle_qm_28x(const struct sr_dev_inst *sdi, char **tokens) { struct sr_datafeed_analog *analog; float fvalue; if (!tokens[1]) return NULL; if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) { sr_err("Invalid float '%s'.", tokens[0]); return NULL; } if (!(analog = g_try_malloc0(sizeof(struct sr_datafeed_analog)))) return NULL; if (!(analog->data = g_try_malloc(sizeof(float)))) return NULL; analog->channels = sdi->channels; analog->num_samples = 1; *analog->data = fvalue; analog->mq = -1; if (!strcmp(tokens[1], "VAC") || !strcmp(tokens[1], "VDC")) { analog->mq = SR_MQ_VOLTAGE; analog->unit = SR_UNIT_VOLT; if (!strcmp(tokens[2], "NORMAL")) { if (tokens[1][1] == 'A') { analog->mqflags |= SR_MQFLAG_AC; analog->mqflags |= SR_MQFLAG_RMS; } else analog->mqflags |= SR_MQFLAG_DC; } else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) { *analog->data = NAN; } else analog->mq = -1; } else if (!strcmp(tokens[1], "dBV") || !strcmp(tokens[1], "dBm")) { analog->mq = SR_MQ_VOLTAGE; if (tokens[1][2] == 'm') analog->unit = SR_UNIT_DECIBEL_MW; else analog->unit = SR_UNIT_DECIBEL_VOLT; analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS; } else if (!strcmp(tokens[1], "CEL") || !strcmp(tokens[1], "FAR")) { if (!strcmp(tokens[2], "NORMAL")) { analog->mq = SR_MQ_TEMPERATURE; if (tokens[1][0] == 'C') analog->unit = SR_UNIT_CELSIUS; else analog->unit = SR_UNIT_FAHRENHEIT; } } else if (!strcmp(tokens[1], "OHM")) { if (!strcmp(tokens[3], "NONE")) { analog->mq = SR_MQ_RESISTANCE; analog->unit = SR_UNIT_OHM; if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) { *analog->data = INFINITY; } else if (strcmp(tokens[2], "NORMAL")) analog->mq = -1; } else if (!strcmp(tokens[3], "OPEN_CIRCUIT")) { analog->mq = SR_MQ_CONTINUITY; analog->unit = SR_UNIT_BOOLEAN; *analog->data = 0.0; } else if (!strcmp(tokens[3], "SHORT_CIRCUIT")) { analog->mq = SR_MQ_CONTINUITY; analog->unit = SR_UNIT_BOOLEAN; *analog->data = 1.0; } } else if (!strcmp(tokens[1], "F") && !strcmp(tokens[2], "NORMAL") && !strcmp(tokens[3], "NONE")) { analog->mq = SR_MQ_CAPACITANCE; analog->unit = SR_UNIT_FARAD; } else if (!strcmp(tokens[1], "AAC") || !strcmp(tokens[1], "ADC")) { analog->mq = SR_MQ_CURRENT; analog->unit = SR_UNIT_AMPERE; if (!strcmp(tokens[2], "NORMAL")) { if (tokens[1][1] == 'A') { analog->mqflags |= SR_MQFLAG_AC; analog->mqflags |= SR_MQFLAG_RMS; } else analog->mqflags |= SR_MQFLAG_DC; } else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) { *analog->data = NAN; } else analog->mq = -1; } if (!strcmp(tokens[1], "Hz") && !strcmp(tokens[2], "NORMAL")) { analog->mq = SR_MQ_FREQUENCY; analog->unit = SR_UNIT_HERTZ; } else if (!strcmp(tokens[1], "PCT") && !strcmp(tokens[2], "NORMAL")) { analog->mq = SR_MQ_DUTY_CYCLE; analog->unit = SR_UNIT_PERCENTAGE; } else if (!strcmp(tokens[1], "S") && !strcmp(tokens[2], "NORMAL")) { analog->mq = SR_MQ_PULSE_WIDTH; analog->unit = SR_UNIT_SECOND; } else if (!strcmp(tokens[1], "SIE") && !strcmp(tokens[2], "NORMAL")) { analog->mq = SR_MQ_CONDUCTANCE; analog->unit = SR_UNIT_SIEMENS; } if (analog->mq == -1) { /* Not a valid measurement. */ g_free(analog->data); g_free(analog); analog = NULL; } return analog; } static void handle_qm_19x_meta(const struct sr_dev_inst *sdi, char **tokens) { struct dev_context *devc; int meas_type, meas_unit, meas_char, i; /* Make sure we have 7 valid tokens. */ for (i = 0; tokens[i] && i < 7; i++); if (i != 7) return; if (strcmp(tokens[1], "1")) /* Invalid measurement. */ return; if (strcmp(tokens[2], "3")) /* Only interested in input from the meter mode source. */ return; devc = sdi->priv; /* Measurement type 11 == absolute, 19 = relative */ meas_type = strtol(tokens[0], NULL, 10); if (meas_type != 11 && meas_type != 19) /* Device is in some mode we don't support. */ return; /* We might get metadata for absolute and relative mode (if the device * is in relative mode). In that case, relative takes precedence. */ if (meas_type == 11 && devc->meas_type == 19) return; meas_unit = strtol(tokens[3], NULL, 10); if (meas_unit == 0) /* Device is turned off. Really. */ return; meas_char = strtol(tokens[4], NULL, 10); devc->mq = devc->unit = -1; devc->mqflags = 0; switch (meas_unit) { case 1: devc->mq = SR_MQ_VOLTAGE; devc->unit = SR_UNIT_VOLT; if (meas_char == 1) devc->mqflags |= SR_MQFLAG_DC; else if (meas_char == 2) devc->mqflags |= SR_MQFLAG_AC; else if (meas_char == 3) devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC; else if (meas_char == 15) devc->mqflags |= SR_MQFLAG_DIODE; break; case 2: devc->mq = SR_MQ_CURRENT; devc->unit = SR_UNIT_AMPERE; if (meas_char == 1) devc->mqflags |= SR_MQFLAG_DC; else if (meas_char == 2) devc->mqflags |= SR_MQFLAG_AC; else if (meas_char == 3) devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC; break; case 3: if (meas_char == 1) { devc->mq = SR_MQ_RESISTANCE; devc->unit = SR_UNIT_OHM; } else if (meas_char == 16) { devc->mq = SR_MQ_CONTINUITY; devc->unit = SR_UNIT_BOOLEAN; } break; case 12: devc->mq = SR_MQ_TEMPERATURE; devc->unit = SR_UNIT_CELSIUS; break; case 13: devc->mq = SR_MQ_TEMPERATURE; devc->unit = SR_UNIT_FAHRENHEIT; break; default: sr_dbg("unknown unit: %d", meas_unit); } if (devc->mq == -1 && devc->unit == -1) return; /* If we got here, we know how to interpret the measurement. */ devc->meas_type = meas_type; if (meas_type == 11) /* Absolute meter reading. */ devc->is_relative = FALSE; else if (!strcmp(tokens[0], "19")) /* Relative meter reading. */ devc->is_relative = TRUE; } static void handle_qm_19x_data(const struct sr_dev_inst *sdi, char **tokens) { struct dev_context *devc; struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; float fvalue; if (!strcmp(tokens[0], "9.9E+37")) { /* An invalid measurement shows up on the display as "OL", but * comes through like this. Since comparing 38-digit floats * is rather problematic, we'll cut through this here. */ fvalue = NAN; } else { if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) { sr_err("Invalid float '%s'.", tokens[0]); return; } } devc = sdi->priv; if (devc->mq == -1 || devc->unit == -1) /* Don't have valid metadata yet. */ return; if (devc->mq == SR_MQ_RESISTANCE && isnan(fvalue)) fvalue = INFINITY; else if (devc->mq == SR_MQ_CONTINUITY) { if (isnan(fvalue)) fvalue = 0.0; else fvalue = 1.0; } analog.channels = sdi->channels; analog.num_samples = 1; analog.data = &fvalue; analog.mq = devc->mq; analog.unit = devc->unit; analog.mqflags = 0; packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(devc->cb_data, &packet); devc->num_samples++; } static void handle_line(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_serial_dev_inst *serial; struct sr_datafeed_packet packet; struct sr_datafeed_analog *analog; int num_tokens, n, i; char cmd[16], **tokens; devc = sdi->priv; serial = sdi->conn; sr_spew("Received line '%s' (%d).", devc->buf, devc->buflen); if (devc->buflen == 1) { if (devc->buf[0] != '0') { /* Not just a CMD_ACK from the query command. */ sr_dbg("Got CMD_ACK '%c'.", devc->buf[0]); devc->expect_response = FALSE; } devc->buflen = 0; return; } analog = NULL; tokens = g_strsplit(devc->buf, ",", 0); if (tokens[0]) { if (devc->profile->model == FLUKE_187 || devc->profile->model == FLUKE_189) { devc->expect_response = FALSE; analog = handle_qm_18x(sdi, tokens); } else if (devc->profile->model == FLUKE_287) { devc->expect_response = FALSE; analog = handle_qm_28x(sdi, tokens); } else if (devc->profile->model == FLUKE_190) { devc->expect_response = FALSE; for (num_tokens = 0; tokens[num_tokens]; num_tokens++); if (num_tokens >= 7) { /* Response to QM: this is a comma-separated list of * fields with metadata about the measurement. This * format can return multiple sets of metadata, * split into sets of 7 tokens each. */ devc->meas_type = 0; for (i = 0; i < num_tokens; i += 7) handle_qm_19x_meta(sdi, tokens + i); if (devc->meas_type) { /* Slip the request in now, before the main * timer loop asks for metadata again. */ n = sprintf(cmd, "QM %d\r", devc->meas_type); if (serial_write(serial, cmd, n) == -1) sr_err("Unable to send QM (measurement): %s.", strerror(errno)); } } else { /* Response to QM measurement request. */ handle_qm_19x_data(sdi, tokens); } } } g_strfreev(tokens); devc->buflen = 0; if (analog) { /* Got a measurement. */ packet.type = SR_DF_ANALOG; packet.payload = analog; sr_session_send(devc->cb_data, &packet); devc->num_samples++; g_free(analog->data); g_free(analog); } } SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_serial_dev_inst *serial; int len; int64_t now, elapsed; (void)fd; if (!(sdi = cb_data)) return TRUE; if (!(devc = sdi->priv)) return TRUE; serial = sdi->conn; if (revents == G_IO_IN) { /* Serial data arrived. */ while(FLUKEDMM_BUFSIZE - devc->buflen - 1 > 0) { len = serial_read(serial, devc->buf + devc->buflen, 1); if (len < 1) break; devc->buflen++; *(devc->buf + devc->buflen) = '\0'; if (*(devc->buf + devc->buflen - 1) == '\r') { *(devc->buf + --devc->buflen) = '\0'; handle_line(sdi); break; } } } if (devc->limit_samples && devc->num_samples >= devc->limit_samples) { sdi->driver->dev_acquisition_stop(sdi, cb_data); return TRUE; } now = g_get_monotonic_time() / 1000; elapsed = now - devc->cmd_sent_at; /* Send query command at poll_period interval, or after 1 second * has elapsed. This will make it easier to recover from any * out-of-sync or temporary disconnect issues. */ if ((devc->expect_response == FALSE && elapsed > devc->profile->poll_period) || elapsed > devc->profile->timeout) { if (serial_write(serial, "QM\r", 3) == -1) sr_err("Unable to send QM: %s.", strerror(errno)); devc->cmd_sent_at = now; devc->expect_response = TRUE; } return TRUE; } libsigrok-0.3.0/hardware/fluke-dmm/api.c0000644000175000017500000001735512332246667015041 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #include #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "fluke-dmm.h" static const int32_t hwopts[] = { SR_CONF_CONN, SR_CONF_SERIALCOMM, }; static const int32_t hwcaps[] = { SR_CONF_MULTIMETER, SR_CONF_LIMIT_SAMPLES, SR_CONF_LIMIT_MSEC, SR_CONF_CONTINUOUS, }; SR_PRIV struct sr_dev_driver flukedmm_driver_info; static struct sr_dev_driver *di = &flukedmm_driver_info; static char *scan_conn[] = { /* 287/289 */ "115200/8n1", /* 187/189 */ "9600/8n1", /* Scopemeter 190 series */ "1200/8n1", NULL }; static const struct flukedmm_profile supported_flukedmm[] = { { FLUKE_187, "187", 100, 1000 }, { FLUKE_189, "189", 100, 1000 }, { FLUKE_287, "287", 100, 1000 }, { FLUKE_190, "199B", 1000, 3500 }, }; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *fluke_scan(const char *conn, const char *serialcomm) { struct sr_dev_inst *sdi; struct drv_context *drvc; struct dev_context *devc; struct sr_channel *ch; struct sr_serial_dev_inst *serial; GSList *devices; int retry, len, i, s; char buf[128], *b, **tokens; if (!(serial = sr_serial_dev_inst_new(conn, serialcomm))) return NULL; if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return NULL; drvc = di->priv; b = buf; retry = 0; devices = NULL; /* We'll try the discovery sequence three times in case the device * is not in an idle state when we send ID. */ while (!devices && retry < 3) { retry++; serial_flush(serial); if (serial_write(serial, "ID\r", 3) == -1) { sr_err("Unable to send ID string: %s.", strerror(errno)); continue; } /* Response is first a CMD_ACK byte (ASCII '0' for OK, * or '1' to signify an error. */ len = 128; serial_readline(serial, &b, &len, 150); if (len != 1) continue; if (buf[0] != '0') continue; /* If CMD_ACK was OK, ID string follows. */ len = 128; serial_readline(serial, &b, &len, 850); if (len < 10) continue; if (strcspn(buf, ",") < 15) /* Looks like it's comma-separated. */ tokens = g_strsplit(buf, ",", 3); else /* Fluke 199B, at least, uses semicolon. */ tokens = g_strsplit(buf, ";", 3); if (!strncmp("FLUKE", tokens[0], 5) && tokens[1] && tokens[2]) { for (i = 0; supported_flukedmm[i].model; i++) { if (strcmp(supported_flukedmm[i].modelname, tokens[0] + 6)) continue; /* Skip leading spaces in version number. */ for (s = 0; tokens[1][s] == ' '; s++); if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Fluke", tokens[0] + 6, tokens[1] + s))) return NULL; if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } devc->profile = &supported_flukedmm[i]; sdi->inst_type = SR_INST_SERIAL; sdi->conn = serial; sdi->priv = devc; sdi->driver = di; if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1"))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); break; } } g_strfreev(tokens); if (devices) /* Found one. */ break; } serial_close(serial); if (!devices) sr_serial_dev_inst_free(serial); return devices; } static GSList *scan(GSList *options) { struct sr_config *src; GSList *l, *devices; int i; const char *conn, *serialcomm; conn = serialcomm = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; case SR_CONF_SERIALCOMM: serialcomm = g_variant_get_string(src->data, NULL); break; } } if (!conn) return NULL; if (serialcomm) { /* Use the provided comm specs. */ devices = fluke_scan(conn, serialcomm); } else { for (i = 0; scan_conn[i]; i++) { if ((devices = fluke_scan(conn, scan_conn[i]))) break; /* The Scopemeter 199B, at least, requires this * after all the 115k/9.6k confusion. */ g_usleep(5000); } } return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int cleanup(void) { return std_dev_clear(di, NULL); } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return SR_ERR_BUG; } switch (id) { case SR_CONF_LIMIT_MSEC: /* TODO: not yet implemented */ if (g_variant_get_uint64(data) == 0) { sr_err("LIMIT_MSEC can't be 0."); return SR_ERR; } devc->limit_msec = g_variant_get_uint64(data); sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec); break; case SR_CONF_LIMIT_SAMPLES: devc->limit_samples = g_variant_get_uint64(data); sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples); break; default: return SR_ERR_NA; } return SR_OK; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; default: return SR_ERR_NA; } return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct sr_serial_dev_inst *serial; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return SR_ERR_BUG; } devc->cb_data = cb_data; /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* Poll every 100ms, or whenever some data comes in. */ serial = sdi->conn; serial_source_add(serial, G_IO_IN, 50, fluke_receive_data, (void *)sdi); if (serial_write(serial, "QM\r", 3) == -1) { sr_err("Unable to send QM: %s.", strerror(errno)); return SR_ERR; } devc->cmd_sent_at = g_get_monotonic_time() / 1000; devc->expect_response = TRUE; return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close, sdi->conn, LOG_PREFIX); } SR_PRIV struct sr_dev_driver flukedmm_driver_info = { .name = "fluke-dmm", .longname = "Fluke 18x/28x series DMMs", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = NULL, .config_set = config_set, .config_list = config_list, .dev_open = std_serial_dev_open, .dev_close = std_serial_dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/fluke-dmm/fluke-dmm.h0000644000175000017500000000331112332246667016141 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #ifndef LIBSIGROK_HARDWARE_FLUKE_DMM_FLUKE_DMM_H #define LIBSIGROK_HARDWARE_FLUKE_DMM_FLUKE_DMM_H #define LOG_PREFIX "fluke-dmm" #define FLUKEDMM_BUFSIZE 256 /* Supported models */ enum { FLUKE_187 = 1, FLUKE_189, FLUKE_287, FLUKE_190, }; /* Supported device profiles */ struct flukedmm_profile { int model; const char *modelname; /* How often to poll, in ms. */ int poll_period; /* If no response received, how long to wait before retrying. */ int timeout; }; /* Private, per-device-instance driver context. */ struct dev_context { const struct flukedmm_profile *profile; uint64_t limit_samples; uint64_t limit_msec; /* Opaque pointer passed in by the frontend. */ void *cb_data; /* Runtime. */ uint64_t num_samples; char buf[FLUKEDMM_BUFSIZE]; int buflen; int64_t cmd_sent_at; int expect_response; int meas_type; int is_relative; int mq; int unit; int mqflags; }; SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data); #endif libsigrok-0.3.0/hardware/victor-dmm/0000755000175000017500000000000012332246734014364 500000000000000libsigrok-0.3.0/hardware/victor-dmm/protocol.h0000644000175000017500000000270512332246667016327 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #ifndef LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H #define LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "victor-dmm" #define DMM_DATA_SIZE 14 /** Private, per-device-instance driver context. */ struct dev_context { /** The current sampling limit (in number of samples). */ uint64_t limit_samples; /** The current sampling limit (in ms). */ uint64_t limit_msec; /** Opaque pointer passed in by the frontend. */ void *cb_data; /** The current number of already received samples. */ uint64_t num_samples; gint64 end_time; }; SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf); #endif libsigrok-0.3.0/hardware/victor-dmm/protocol.c0000644000175000017500000001526112332246667016323 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "protocol.h" /* Reverse the high nibble into the low nibble */ static uint8_t decode_digit(uint8_t in) { uint8_t out, i; out = 0; in >>= 4; for (i = 0x08; i; i >>= 1) { out >>= 1; if (in & i) out |= 0x08; } return out; } static void decode_buf(struct sr_dev_inst *sdi, unsigned char *data) { struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; struct dev_context *devc; long factor, ivalue; uint8_t digits[4]; gboolean is_duty, is_continuity, is_diode, is_ac, is_dc, is_auto; gboolean is_hold, is_max, is_min, is_relative, minus; float fvalue; devc = sdi->priv; digits[0] = decode_digit(data[12]); digits[1] = decode_digit(data[11]); digits[2] = decode_digit(data[10]); digits[3] = decode_digit(data[9]); if (digits[0] == 0x0f && digits[1] == 0x00 && digits[2] == 0x0a && digits[3] == 0x0f) /* The "over limit" (OL) display comes through like this */ ivalue = -1; else if (digits[0] > 9 || digits[1] > 9 || digits[2] > 9 || digits[3] > 9) /* An invalid digit in any position denotes no value. */ ivalue = -2; else { ivalue = digits[0] * 1000; ivalue += digits[1] * 100; ivalue += digits[2] * 10; ivalue += digits[3]; } /* Decimal point position */ factor = 0; switch (data[7] >> 4) { case 0x00: factor = 0; break; case 0x02: factor = 1; break; case 0x04: factor = 2; break; case 0x08: factor = 3; break; default: sr_err("Unknown decimal point byte: 0x%.2x.", data[7]); break; } /* Minus flag */ minus = data[2] & 0x01; /* Mode detail symbols on the right side of the digits */ is_duty = is_continuity = is_diode = FALSE; switch (data[4]) { case 0x00: /* None. */ break; case 0x01: /* Micro */ factor += 6; break; case 0x02: /* Milli */ factor += 3; break; case 0x04: /* Kilo */ ivalue *= 1000; break; case 0x08: /* Mega */ ivalue *= 1000000; break; case 0x10: /* Continuity shows up as Ohm + this bit */ is_continuity = TRUE; break; case 0x20: /* Diode tester is Volt + this bit */ is_diode = TRUE; break; case 0x40: is_duty = TRUE; break; case 0x80: /* Never seen */ sr_dbg("Unknown mode right detail: 0x%.2x.", data[4]); break; default: sr_dbg("Unknown/invalid mode right detail: 0x%.2x.", data[4]); break; } /* Scale flags on the right, continued */ is_max = is_min = FALSE; if (data[5] & 0x04) is_max = TRUE; if (data[5] & 0x08) is_min = TRUE; if (data[5] & 0x40) /* Nano */ factor += 9; /* Mode detail symbols on the left side of the digits */ is_auto = is_dc = is_ac = is_hold = is_relative = FALSE; if (data[6] & 0x04) is_auto = TRUE; if (data[6] & 0x08) is_dc = TRUE; if (data[6] & 0x10) is_ac = TRUE; if (data[6] & 0x20) is_relative = TRUE; if (data[6] & 0x40) is_hold = TRUE; fvalue = (float)ivalue / pow(10, factor); if (minus) fvalue = -fvalue; memset(&analog, 0, sizeof(struct sr_datafeed_analog)); /* Measurement mode */ analog.mq = -1; switch (data[3]) { case 0x00: if (is_duty) { analog.mq = SR_MQ_DUTY_CYCLE; analog.unit = SR_UNIT_PERCENTAGE; } else sr_dbg("Unknown measurement mode: %.2x.", data[3]); break; case 0x01: if (is_diode) { analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; analog.mqflags |= SR_MQFLAG_DIODE; if (ivalue < 0) fvalue = NAN; } else { if (ivalue < 0) break; analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; if (is_ac) analog.mqflags |= SR_MQFLAG_AC; if (is_dc) analog.mqflags |= SR_MQFLAG_DC; } break; case 0x02: analog.mq = SR_MQ_CURRENT; analog.unit = SR_UNIT_AMPERE; if (is_ac) analog.mqflags |= SR_MQFLAG_AC; if (is_dc) analog.mqflags |= SR_MQFLAG_DC; break; case 0x04: if (is_continuity) { analog.mq = SR_MQ_CONTINUITY; analog.unit = SR_UNIT_BOOLEAN; fvalue = ivalue < 0 ? 0.0 : 1.0; } else { analog.mq = SR_MQ_RESISTANCE; analog.unit = SR_UNIT_OHM; if (ivalue < 0) fvalue = INFINITY; } break; case 0x08: /* Never seen */ sr_dbg("Unknown measurement mode: 0x%.2x.", data[3]); break; case 0x10: analog.mq = SR_MQ_FREQUENCY; analog.unit = SR_UNIT_HERTZ; break; case 0x20: analog.mq = SR_MQ_CAPACITANCE; analog.unit = SR_UNIT_FARAD; break; case 0x40: analog.mq = SR_MQ_TEMPERATURE; analog.unit = SR_UNIT_CELSIUS; break; case 0x80: analog.mq = SR_MQ_TEMPERATURE; analog.unit = SR_UNIT_FAHRENHEIT; break; default: sr_dbg("Unknown/invalid measurement mode: 0x%.2x.", data[3]); break; } if (analog.mq == -1) return; if (is_auto) analog.mqflags |= SR_MQFLAG_AUTORANGE; if (is_hold) analog.mqflags |= SR_MQFLAG_HOLD; if (is_max) analog.mqflags |= SR_MQFLAG_MAX; if (is_min) analog.mqflags |= SR_MQFLAG_MIN; if (is_relative) analog.mqflags |= SR_MQFLAG_RELATIVE; analog.channels = sdi->channels; analog.num_samples = 1; analog.data = &fvalue; packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(devc->cb_data, &packet); devc->num_samples++; } SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf) { GString *dbg; int i; unsigned char data[DMM_DATA_SIZE]; unsigned char obfuscation[DMM_DATA_SIZE] = "jodenxunickxia"; unsigned char shuffle[DMM_DATA_SIZE] = { 6, 13, 5, 11, 2, 7, 9, 8, 3, 10, 12, 0, 4, 1 }; for (i = 0; i < DMM_DATA_SIZE && buf[i] == 0; i++); if (i == DMM_DATA_SIZE) { /* This DMM outputs all zeroes from time to time, just ignore it. */ sr_dbg("Received all zeroes."); return SR_OK; } /* Deobfuscate and reorder data. */ for (i = 0; i < DMM_DATA_SIZE; i++) data[shuffle[i]] = (buf[i] - obfuscation[i]) & 0xff; if (sr_log_loglevel_get() >= SR_LOG_SPEW) { dbg = g_string_sized_new(128); g_string_printf(dbg, "Deobfuscated."); for (i = 0; i < DMM_DATA_SIZE; i++) g_string_append_printf(dbg, " %.2x", data[i]); sr_spew("%s", dbg->str); g_string_free(dbg, TRUE); } decode_buf(sdi, data); return SR_OK; } libsigrok-0.3.0/hardware/victor-dmm/api.c0000644000175000017500000002467012332246667015237 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "protocol.h" #define VICTOR_VID 0x1244 #define VICTOR_PID 0xd237 #define VICTOR_VENDOR "Victor" #define VICTOR_INTERFACE 0 #define VICTOR_ENDPOINT LIBUSB_ENDPOINT_IN | 1 SR_PRIV struct sr_dev_driver victor_dmm_driver_info; static struct sr_dev_driver *di = &victor_dmm_driver_info; static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data); static const int32_t hwopts[] = { SR_CONF_CONN, }; static const int32_t hwcaps[] = { SR_CONF_MULTIMETER, SR_CONF_LIMIT_MSEC, SR_CONF_LIMIT_SAMPLES, SR_CONF_CONTINUOUS, }; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_channel *ch; struct libusb_device_descriptor des; libusb_device **devlist; GSList *devices; int ret, devcnt, i; (void)options; drvc = di->priv; devices = NULL; libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) { sr_warn("Failed to get device descriptor: %s", libusb_error_name(ret)); continue; } if (des.idVendor != VICTOR_VID || des.idProduct != VICTOR_PID) continue; devcnt = g_slist_length(drvc->instances); if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE, VICTOR_VENDOR, NULL, NULL))) return NULL; sdi->driver = di; if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) return NULL; sdi->priv = devc; if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1"))) return NULL; sdi->channels = g_slist_append(NULL, ch); if (!(sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL))) return NULL; sdi->inst_type = SR_INST_USB; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); } libusb_free_device_list(devlist, 1); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int dev_open(struct sr_dev_inst *sdi) { struct drv_context *drvc = di->priv; struct sr_usb_dev_inst *usb; libusb_device **devlist; int ret, i; if (!di->priv) { sr_err("Driver was not initialized."); return SR_ERR; } usb = sdi->conn; libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if (libusb_get_bus_number(devlist[i]) != usb->bus || libusb_get_device_address(devlist[i]) != usb->address) continue; if ((ret = libusb_open(devlist[i], &usb->devhdl))) { sr_err("Failed to open device: %s.", libusb_error_name(ret)); return SR_ERR; } break; } libusb_free_device_list(devlist, 1); if (!devlist[i]) { sr_err("Device not found."); return SR_ERR; } /* The device reports as HID class, so the kernel would have * claimed it. */ if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) { if ((ret = libusb_detach_kernel_driver(usb->devhdl, 0)) < 0) { sr_err("Failed to detach kernel driver: %s.", libusb_error_name(ret)); return SR_ERR; } } if ((ret = libusb_claim_interface(usb->devhdl, VICTOR_INTERFACE))) { sr_err("Failed to claim interface: %s.", libusb_error_name(ret)); return SR_ERR; } sdi->status = SR_ST_ACTIVE; return SR_OK; } static int dev_close(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; if (!di->priv) { sr_err("Driver was not initialized."); return SR_ERR; } usb = sdi->conn; if (!usb->devhdl) /* Nothing to do. */ return SR_OK; libusb_release_interface(usb->devhdl, VICTOR_INTERFACE); libusb_close(usb->devhdl); usb->devhdl = NULL; sdi->status = SR_ST_INACTIVE; return SR_OK; } static int cleanup(void) { int ret; struct drv_context *drvc; if (!(drvc = di->priv)) /* Can get called on an unused driver, doesn't matter. */ return SR_OK; ret = std_dev_clear(di, NULL); g_free(drvc); di->priv = NULL; return ret; } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct sr_usb_dev_inst *usb; char str[128]; (void)cg; switch (id) { case SR_CONF_CONN: if (!sdi || !sdi->conn) return SR_ERR_ARG; usb = sdi->conn; snprintf(str, 128, "%d.%d", usb->bus, usb->address); *data = g_variant_new_string(str); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; gint64 now; int ret; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!di->priv) { sr_err("Driver was not initialized."); return SR_ERR; } devc = sdi->priv; ret = SR_OK; switch (id) { case SR_CONF_LIMIT_MSEC: devc->limit_msec = g_variant_get_uint64(data); now = g_get_monotonic_time() / 1000; devc->end_time = now + devc->limit_msec; sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec); break; case SR_CONF_LIMIT_SAMPLES: devc->limit_samples = g_variant_get_uint64(data); sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples); break; default: ret = SR_ERR_NA; } return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; default: return SR_ERR_NA; } return SR_OK; } static void receive_transfer(struct libusb_transfer *transfer) { struct dev_context *devc; struct sr_dev_inst *sdi; int ret; sdi = transfer->user_data; devc = sdi->priv; if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { /* USB device was unplugged. */ dev_acquisition_stop(sdi, sdi); } else if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { sr_dbg("Got %d-byte packet.", transfer->actual_length); if (transfer->actual_length == DMM_DATA_SIZE) { victor_dmm_receive_data(sdi, transfer->buffer); if (devc->limit_samples) { if (devc->num_samples >= devc->limit_samples) dev_acquisition_stop(sdi, sdi); } } } /* Anything else is either an error or a timeout, which is fine: * we were just going to send another transfer request anyway. */ if (sdi->status == SR_ST_ACTIVE) { /* Send the same request again. */ if ((ret = libusb_submit_transfer(transfer) != 0)) { sr_err("Unable to resubmit transfer: %s.", libusb_error_name(ret)); g_free(transfer->buffer); libusb_free_transfer(transfer); dev_acquisition_stop(sdi, sdi); } } else { /* This was the last transfer we're going to receive, so * clean up now. */ g_free(transfer->buffer); libusb_free_transfer(transfer); } } static int handle_events(int fd, int revents, void *cb_data) { struct dev_context *devc; struct drv_context *drvc = di->priv; struct sr_datafeed_packet packet; struct sr_dev_inst *sdi; struct timeval tv; gint64 now; (void)fd; (void)revents; sdi = cb_data; devc = sdi->priv; if (devc->limit_msec) { now = g_get_monotonic_time() / 1000; if (now > devc->end_time) dev_acquisition_stop(sdi, sdi); } if (sdi->status == SR_ST_STOPPING) { usb_source_remove(drvc->sr_ctx); dev_close(sdi); packet.type = SR_DF_END; sr_session_send(cb_data, &packet); } memset(&tv, 0, sizeof(struct timeval)); libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, NULL); return TRUE; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct drv_context *drvc = di->priv; struct sr_usb_dev_inst *usb; struct libusb_transfer *transfer; int ret; unsigned char *buf; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!di->priv) { sr_err("Driver was not initialized."); return SR_ERR; } devc = sdi->priv; usb = sdi->conn; devc->cb_data = cb_data; /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); usb_source_add(drvc->sr_ctx, 100, handle_events, (void *)sdi); buf = g_try_malloc(DMM_DATA_SIZE); transfer = libusb_alloc_transfer(0); /* Each transfer request gets 100ms to arrive before it's restarted. * The device only sends 1 transfer/second no matter how many * times you ask, but we want to keep step with the USB events * handling above. */ libusb_fill_interrupt_transfer(transfer, usb->devhdl, VICTOR_ENDPOINT, buf, DMM_DATA_SIZE, receive_transfer, cb_data, 100); if ((ret = libusb_submit_transfer(transfer) != 0)) { sr_err("Unable to submit transfer: %s.", libusb_error_name(ret)); libusb_free_transfer(transfer); g_free(buf); return SR_ERR; } return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; if (!di->priv) { sr_err("Driver was not initialized."); return SR_ERR; } if (sdi->status != SR_ST_ACTIVE) { sr_err("Device not active, can't stop acquisition."); return SR_ERR; } sdi->status = SR_ST_STOPPING; return SR_OK; } SR_PRIV struct sr_dev_driver victor_dmm_driver_info = { .name = "victor-dmm", .longname = "Victor DMMs", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/fx2lafw/0000755000175000017500000000000012332246734013654 500000000000000libsigrok-0.3.0/hardware/fx2lafw/protocol.h0000644000175000017500000000657512332246667015630 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen * Copyright (C) 2012 Joel Holdsworth * * 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 . */ #ifndef LIBSIGROK_HARDWARE_FX2LAFW_PROTOCOL_H #define LIBSIGROK_HARDWARE_FX2LAFW_PROTOCOL_H #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "fx2lafw" #define USB_INTERFACE 0 #define USB_CONFIGURATION 1 #define NUM_TRIGGER_STAGES 4 #define TRIGGER_TYPE "01" #define MAX_RENUM_DELAY_MS 3000 #define NUM_SIMUL_TRANSFERS 32 #define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2) #define FX2LAFW_REQUIRED_VERSION_MAJOR 1 #define MAX_8BIT_SAMPLE_RATE SR_MHZ(24) #define MAX_16BIT_SAMPLE_RATE SR_MHZ(12) /* 6 delay states of up to 256 clock ticks */ #define MAX_SAMPLE_DELAY (6 * 256) #define DEV_CAPS_16BIT_POS 0 #define DEV_CAPS_16BIT (1 << DEV_CAPS_16BIT_POS) struct fx2lafw_profile { uint16_t vid; uint16_t pid; const char *vendor; const char *model; const char *model_version; const char *firmware; uint32_t dev_caps; const char *usb_manufacturer; const char *usb_product; }; struct dev_context { const struct fx2lafw_profile *profile; /* * Since we can't keep track of an fx2lafw device after upgrading * the firmware (it renumerates into a different device address * after the upgrade) this is like a global lock. No device will open * until a proper delay after the last device was upgraded. */ int64_t fw_updated; /* Device/capture settings */ uint64_t cur_samplerate; uint64_t limit_samples; /* Operational settings */ gboolean trigger_fired; gboolean acq_aborted; gboolean sample_wide; uint16_t trigger_mask[NUM_TRIGGER_STAGES]; uint16_t trigger_value[NUM_TRIGGER_STAGES]; unsigned int trigger_stage; uint16_t trigger_buffer[NUM_TRIGGER_STAGES]; unsigned int sent_samples; int submitted_transfers; int empty_transfer_count; void *cb_data; unsigned int num_transfers; struct libusb_transfer **transfers; struct sr_context *ctx; }; SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi); SR_PRIV gboolean fx2lafw_check_conf_profile(libusb_device *dev); SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di); SR_PRIV int fx2lafw_configure_channels(const struct sr_dev_inst *sdi); SR_PRIV struct dev_context *fx2lafw_dev_new(void); SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc); SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer); SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc); SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc); SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc); #endif libsigrok-0.3.0/hardware/fx2lafw/protocol.c0000644000175000017500000003721112332246667015612 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen * Copyright (C) 2012 Joel Holdsworth * * 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 . */ #include "protocol.h" /* Protocol commands */ #define CMD_GET_FW_VERSION 0xb0 #define CMD_START 0xb1 #define CMD_GET_REVID_VERSION 0xb2 #define CMD_START_FLAGS_WIDE_POS 5 #define CMD_START_FLAGS_CLK_SRC_POS 6 #define CMD_START_FLAGS_SAMPLE_8BIT (0 << CMD_START_FLAGS_WIDE_POS) #define CMD_START_FLAGS_SAMPLE_16BIT (1 << CMD_START_FLAGS_WIDE_POS) #define CMD_START_FLAGS_CLK_30MHZ (0 << CMD_START_FLAGS_CLK_SRC_POS) #define CMD_START_FLAGS_CLK_48MHZ (1 << CMD_START_FLAGS_CLK_SRC_POS) #pragma pack(push, 1) struct version_info { uint8_t major; uint8_t minor; }; struct cmd_start_acquisition { uint8_t flags; uint8_t sample_delay_h; uint8_t sample_delay_l; }; #pragma pack(pop) static int command_get_fw_version(libusb_device_handle *devhdl, struct version_info *vi) { int ret; ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN, CMD_GET_FW_VERSION, 0x0000, 0x0000, (unsigned char *)vi, sizeof(struct version_info), 100); if (ret < 0) { sr_err("Unable to get version info: %s.", libusb_error_name(ret)); return SR_ERR; } return SR_OK; } static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid) { struct sr_usb_dev_inst *usb = sdi->conn; libusb_device_handle *devhdl = usb->devhdl; int ret; ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN, CMD_GET_REVID_VERSION, 0x0000, 0x0000, revid, 1, 100); if (ret < 0) { sr_err("Unable to get REVID: %s.", libusb_error_name(ret)); return SR_ERR; } return SR_OK; } SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi) { struct dev_context *devc = sdi->priv; struct sr_usb_dev_inst *usb = sdi->conn; libusb_device_handle *devhdl = usb->devhdl; uint64_t samplerate = devc->cur_samplerate; gboolean samplewide = devc->sample_wide; struct cmd_start_acquisition cmd = { 0 }; int delay = 0, ret; /* Compute the sample rate. */ if (samplewide && samplerate > MAX_16BIT_SAMPLE_RATE) { sr_err("Unable to sample at %" PRIu64 "Hz " "when collecting 16-bit samples.", samplerate); return SR_ERR; } if ((SR_MHZ(48) % samplerate) == 0) { cmd.flags = CMD_START_FLAGS_CLK_48MHZ; delay = SR_MHZ(48) / samplerate - 1; if (delay > MAX_SAMPLE_DELAY) delay = 0; } if (delay == 0 && (SR_MHZ(30) % samplerate) == 0) { cmd.flags = CMD_START_FLAGS_CLK_30MHZ; delay = SR_MHZ(30) / samplerate - 1; } sr_info("GPIF delay = %d, clocksource = %sMHz.", delay, (cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30"); if (delay <= 0 || delay > MAX_SAMPLE_DELAY) { sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate); return SR_ERR; } cmd.sample_delay_h = (delay >> 8) & 0xff; cmd.sample_delay_l = delay & 0xff; /* Select the sampling width. */ cmd.flags |= samplewide ? CMD_START_FLAGS_SAMPLE_16BIT : CMD_START_FLAGS_SAMPLE_8BIT; /* Send the control message. */ ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, CMD_START, 0x0000, 0x0000, (unsigned char *)&cmd, sizeof(cmd), 100); if (ret < 0) { sr_err("Unable to send start command: %s.", libusb_error_name(ret)); return SR_ERR; } return SR_OK; } /** * Check the USB configuration to determine if this is an fx2lafw device. * * @return TRUE if the device's configuration profile match fx2lafw * configuration, FALSE otherwise. */ SR_PRIV gboolean fx2lafw_check_conf_profile(libusb_device *dev) { struct libusb_device_descriptor des; struct libusb_device_handle *hdl; gboolean ret; unsigned char strdesc[64]; hdl = NULL; ret = FALSE; while (!ret) { /* Assume the FW has not been loaded, unless proven wrong. */ if (libusb_get_device_descriptor(dev, &des) != 0) break; if (libusb_open(dev, &hdl) != 0) break; if (libusb_get_string_descriptor_ascii(hdl, des.iManufacturer, strdesc, sizeof(strdesc)) < 0) break; if (strncmp((const char *)strdesc, "sigrok", 6)) break; if (libusb_get_string_descriptor_ascii(hdl, des.iProduct, strdesc, sizeof(strdesc)) < 0) break; if (strncmp((const char *)strdesc, "fx2lafw", 7)) break; /* If we made it here, it must be an fx2lafw. */ ret = TRUE; } if (hdl) libusb_close(hdl); return ret; } SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) { libusb_device **devlist; struct sr_usb_dev_inst *usb; struct libusb_device_descriptor des; struct dev_context *devc; struct drv_context *drvc; struct version_info vi; int ret, skip, i, device_count; uint8_t revid; drvc = di->priv; devc = sdi->priv; usb = sdi->conn; if (sdi->status == SR_ST_ACTIVE) /* Device is already in use. */ return SR_ERR; skip = 0; device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); if (device_count < 0) { sr_err("Failed to get device list: %s.", libusb_error_name(device_count)); return SR_ERR; } for (i = 0; i < device_count; i++) { if ((ret = libusb_get_device_descriptor(devlist[i], &des))) { sr_err("Failed to get device descriptor: %s.", libusb_error_name(ret)); continue; } if (des.idVendor != devc->profile->vid || des.idProduct != devc->profile->pid) continue; if (sdi->status == SR_ST_INITIALIZING) { if (skip != sdi->index) { /* Skip devices of this type that aren't the one we want. */ skip += 1; continue; } } else if (sdi->status == SR_ST_INACTIVE) { /* * This device is fully enumerated, so we need to find * this device by vendor, product, bus and address. */ if (libusb_get_bus_number(devlist[i]) != usb->bus || libusb_get_device_address(devlist[i]) != usb->address) /* This is not the one. */ continue; } if (!(ret = libusb_open(devlist[i], &usb->devhdl))) { if (usb->address == 0xff) /* * First time we touch this device after FW * upload, so we don't know the address yet. */ usb->address = libusb_get_device_address(devlist[i]); } else { sr_err("Failed to open device: %s.", libusb_error_name(ret)); break; } ret = command_get_fw_version(usb->devhdl, &vi); if (ret != SR_OK) { sr_err("Failed to get firmware version."); break; } ret = command_get_revid_version(sdi, &revid); if (ret != SR_OK) { sr_err("Failed to get REVID."); break; } /* * Changes in major version mean incompatible/API changes, so * bail out if we encounter an incompatible version. * Different minor versions are OK, they should be compatible. */ if (vi.major != FX2LAFW_REQUIRED_VERSION_MAJOR) { sr_err("Expected firmware version %d.x, " "got %d.%d.", FX2LAFW_REQUIRED_VERSION_MAJOR, vi.major, vi.minor); break; } sdi->status = SR_ST_ACTIVE; sr_info("Opened device %d on %d.%d, " "interface %d, firmware %d.%d.", sdi->index, usb->bus, usb->address, USB_INTERFACE, vi.major, vi.minor); sr_info("Detected REVID=%d, it's a Cypress CY7C68013%s.", revid, (revid != 1) ? " (FX2)" : "A (FX2LP)"); break; } libusb_free_device_list(devlist, 1); if (sdi->status != SR_ST_ACTIVE) return SR_ERR; return SR_OK; } SR_PRIV int fx2lafw_configure_channels(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_channel *ch; GSList *l; int channel_bit, stage, i; char *tc; devc = sdi->priv; for (i = 0; i < NUM_TRIGGER_STAGES; i++) { devc->trigger_mask[i] = 0; devc->trigger_value[i] = 0; } stage = -1; for (l = sdi->channels; l; l = l->next) { ch = (struct sr_channel *)l->data; if (ch->enabled == FALSE) continue; if (ch->index > 7) devc->sample_wide = TRUE; channel_bit = 1 << (ch->index); if (!(ch->trigger)) continue; stage = 0; for (tc = ch->trigger; *tc; tc++) { devc->trigger_mask[stage] |= channel_bit; if (*tc == '1') devc->trigger_value[stage] |= channel_bit; stage++; if (stage > NUM_TRIGGER_STAGES) return SR_ERR; } } if (stage == -1) { /* * We didn't configure any triggers, make sure acquisition * doesn't wait for any. */ devc->trigger_fired = TRUE; } else { devc->trigger_fired = FALSE; devc->trigger_stage = 0; } return SR_OK; } SR_PRIV struct dev_context *fx2lafw_dev_new(void) { struct dev_context *devc; if (!(devc = g_try_malloc(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } devc->profile = NULL; devc->fw_updated = 0; devc->cur_samplerate = 0; devc->limit_samples = 0; devc->sample_wide = FALSE; return devc; } SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc) { int i; devc->acq_aborted = TRUE; for (i = devc->num_transfers - 1; i >= 0; i--) { if (devc->transfers[i]) libusb_cancel_transfer(devc->transfers[i]); } } static void finish_acquisition(struct dev_context *devc) { struct sr_datafeed_packet packet; /* Terminate session. */ packet.type = SR_DF_END; sr_session_send(devc->cb_data, &packet); /* Remove fds from polling. */ usb_source_remove(devc->ctx); devc->num_transfers = 0; g_free(devc->transfers); } static void free_transfer(struct libusb_transfer *transfer) { struct dev_context *devc; unsigned int i; devc = transfer->user_data; g_free(transfer->buffer); transfer->buffer = NULL; libusb_free_transfer(transfer); for (i = 0; i < devc->num_transfers; i++) { if (devc->transfers[i] == transfer) { devc->transfers[i] = NULL; break; } } devc->submitted_transfers--; if (devc->submitted_transfers == 0) finish_acquisition(devc); } static void resubmit_transfer(struct libusb_transfer *transfer) { int ret; if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS) return; free_transfer(transfer); /* TODO: Stop session? */ sr_err("%s: %s", __func__, libusb_error_name(ret)); } SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer) { gboolean packet_has_error = FALSE; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; struct dev_context *devc; unsigned int trigger_offset, num_samples; int cur_sample_count, sample_width, i; uint8_t *cur_buf; uint16_t cur_sample; devc = transfer->user_data; /* * If acquisition has already ended, just free any queued up * transfer that come in. */ if (devc->acq_aborted) { free_transfer(transfer); return; } sr_info("receive_transfer(): status %d received %d bytes.", transfer->status, transfer->actual_length); /* Save incoming transfer before reusing the transfer struct. */ cur_buf = transfer->buffer; sample_width = devc->sample_wide ? 2 : 1; cur_sample_count = transfer->actual_length / sample_width; switch (transfer->status) { case LIBUSB_TRANSFER_NO_DEVICE: fx2lafw_abort_acquisition(devc); free_transfer(transfer); return; case LIBUSB_TRANSFER_COMPLETED: case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ break; default: packet_has_error = TRUE; break; } if (transfer->actual_length == 0 || packet_has_error) { devc->empty_transfer_count++; if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { /* * The FX2 gave up. End the acquisition, the frontend * will work out that the samplecount is short. */ fx2lafw_abort_acquisition(devc); free_transfer(transfer); } else { resubmit_transfer(transfer); } return; } else { devc->empty_transfer_count = 0; } trigger_offset = 0; if (!devc->trigger_fired) { for (i = 0; i < cur_sample_count; i++) { cur_sample = devc->sample_wide ? *((uint16_t *)cur_buf + i) : *((uint8_t *)cur_buf + i); if ((cur_sample & devc->trigger_mask[devc->trigger_stage]) == devc->trigger_value[devc->trigger_stage]) { /* Match on this trigger stage. */ devc->trigger_buffer[devc->trigger_stage] = cur_sample; devc->trigger_stage++; if (devc->trigger_stage == NUM_TRIGGER_STAGES || devc->trigger_mask[devc->trigger_stage] == 0) { /* Match on all trigger stages, we're done. */ trigger_offset = i; /* * TODO: Send pre-trigger buffer to session bus. * Tell the frontend we hit the trigger here. */ packet.type = SR_DF_TRIGGER; packet.payload = NULL; sr_session_send(devc->cb_data, &packet); /* * Send the samples that triggered it, * since we're skipping past them. */ packet.type = SR_DF_LOGIC; packet.payload = &logic; num_samples = cur_sample_count - trigger_offset; if (devc->limit_samples && num_samples > devc->limit_samples - devc->sent_samples) num_samples = devc->limit_samples - devc->sent_samples; logic.length = num_samples * sample_width; logic.unitsize = sample_width; logic.data = cur_buf + trigger_offset * sample_width; sr_session_send(devc->cb_data, &packet); devc->sent_samples += num_samples; devc->trigger_fired = TRUE; break; } } else if (devc->trigger_stage > 0) { /* * We had a match before, but not in the next sample. However, we may * have a match on this stage in the next bit -- trigger on 0001 will * fail on seeing 00001, so we need to go back to stage 0 -- but at * the next sample from the one that matched originally, which the * counter increment at the end of the loop takes care of. */ i -= devc->trigger_stage; if (i < -1) i = -1; /* Oops, went back past this buffer. */ /* Reset trigger stage. */ devc->trigger_stage = 0; } } } else if (devc->sent_samples < devc->limit_samples) { /* Send the incoming transfer to the session bus. */ packet.type = SR_DF_LOGIC; packet.payload = &logic; if (devc->sent_samples + cur_sample_count > devc->limit_samples) num_samples = devc->limit_samples - devc->sent_samples; else num_samples = cur_sample_count; logic.length = num_samples * sample_width; logic.unitsize = sample_width; logic.data = cur_buf; sr_session_send(devc->cb_data, &packet); devc->sent_samples += cur_sample_count; } if (devc->limit_samples && devc->sent_samples >= devc->limit_samples) { fx2lafw_abort_acquisition(devc); free_transfer(transfer); return; } resubmit_transfer(transfer); } static unsigned int to_bytes_per_ms(unsigned int samplerate) { return samplerate / 1000; } SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc) { size_t s; /* * The buffer should be large enough to hold 10ms of data and * a multiple of 512. */ s = 10 * to_bytes_per_ms(devc->cur_samplerate); return (s + 511) & ~511; } SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc) { unsigned int n; /* Total buffer size should be able to hold about 500ms of data. */ n = (500 * to_bytes_per_ms(devc->cur_samplerate) / fx2lafw_get_buffer_size(devc)); if (n > NUM_SIMUL_TRANSFERS) return NUM_SIMUL_TRANSFERS; return n; } SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc) { size_t total_size; unsigned int timeout; total_size = fx2lafw_get_buffer_size(devc) * fx2lafw_get_number_of_transfers(devc); timeout = total_size / to_bytes_per_ms(devc->cur_samplerate); return timeout + timeout / 4; /* Leave a headroom of 25% percent. */ } libsigrok-0.3.0/hardware/fx2lafw/api.c0000644000175000017500000003471412332246667014527 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen * Copyright (C) 2012 Joel Holdsworth * * 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 . */ #include "protocol.h" static const struct fx2lafw_profile supported_fx2[] = { /* * CWAV USBee AX * EE Electronics ESLA201A * ARMFLY AX-Pro */ { 0x08a9, 0x0014, "CWAV", "USBee AX", NULL, FIRMWARE_DIR "/fx2lafw-cwav-usbeeax.fw", 0, NULL, NULL}, /* * CWAV USBee DX * XZL-Studio DX */ { 0x08a9, 0x0015, "CWAV", "USBee DX", NULL, FIRMWARE_DIR "/fx2lafw-cwav-usbeedx.fw", DEV_CAPS_16BIT, NULL, NULL }, /* * CWAV USBee SX */ { 0x08a9, 0x0009, "CWAV", "USBee SX", NULL, FIRMWARE_DIR "/fx2lafw-cwav-usbeesx.fw", 0, NULL, NULL}, /* * Saleae Logic * EE Electronics ESLA100 * Robomotic MiniLogic * Robomotic BugLogic 3 */ { 0x0925, 0x3881, "Saleae", "Logic", NULL, FIRMWARE_DIR "/fx2lafw-saleae-logic.fw", 0, NULL, NULL}, /* * Default Cypress FX2 without EEPROM, e.g.: * Lcsoft Mini Board * Braintechnology USB Interface V2.x */ { 0x04B4, 0x8613, "Cypress", "FX2", NULL, FIRMWARE_DIR "/fx2lafw-cypress-fx2.fw", DEV_CAPS_16BIT, NULL, NULL }, /* * Braintechnology USB-LPS */ { 0x16d0, 0x0498, "Braintechnology", "USB-LPS", NULL, FIRMWARE_DIR "/fx2lafw-braintechnology-usb-lps.fw", DEV_CAPS_16BIT, NULL, NULL }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; static const int32_t hwopts[] = { SR_CONF_CONN, }; static const int32_t hwcaps[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_TRIGGER_TYPE, SR_CONF_SAMPLERATE, /* These are really implemented in the driver, not the hardware. */ SR_CONF_LIMIT_SAMPLES, SR_CONF_CONTINUOUS, }; static const char *channel_names[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", NULL, }; static const uint64_t samplerates[] = { SR_KHZ(20), SR_KHZ(25), SR_KHZ(50), SR_KHZ(100), SR_KHZ(200), SR_KHZ(250), SR_KHZ(500), SR_MHZ(1), SR_MHZ(2), SR_MHZ(3), SR_MHZ(4), SR_MHZ(6), SR_MHZ(8), SR_MHZ(12), SR_MHZ(16), SR_MHZ(24), }; SR_PRIV struct sr_dev_driver fx2lafw_driver_info; static struct sr_dev_driver *di = &fx2lafw_driver_info; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_usb_dev_inst *usb; struct sr_channel *ch; struct sr_config *src; const struct fx2lafw_profile *prof; GSList *l, *devices, *conn_devices; struct libusb_device_descriptor des; libusb_device **devlist; struct libusb_device_handle *hdl; int devcnt, num_logic_channels, ret, i, j; const char *conn; char manufacturer[64], product[64]; drvc = di->priv; conn = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; } } if (conn) conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); else conn_devices = NULL; /* Find all fx2lafw compatible devices and upload firmware to them. */ devices = NULL; libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if (conn) { usb = NULL; for (l = conn_devices; l; l = l->next) { usb = l->data; if (usb->bus == libusb_get_bus_number(devlist[i]) && usb->address == libusb_get_device_address(devlist[i])) break; } if (!l) /* This device matched none of the ones that * matched the conn specification. */ continue; } if ((ret = libusb_get_device_descriptor( devlist[i], &des)) != 0) { sr_warn("Failed to get device descriptor: %s.", libusb_error_name(ret)); continue; } if ((ret = libusb_open(devlist[i], &hdl)) < 0) continue; if (des.iManufacturer == 0) { manufacturer[0] = '\0'; } else if ((ret = libusb_get_string_descriptor_ascii(hdl, des.iManufacturer, (unsigned char *) manufacturer, sizeof(manufacturer))) < 0) { sr_warn("Failed to get manufacturer string descriptor: %s.", libusb_error_name(ret)); continue; } if (des.iProduct == 0) { product[0] = '\0'; } else if ((ret = libusb_get_string_descriptor_ascii(hdl, des.iProduct, (unsigned char *) product, sizeof(product))) < 0) { sr_warn("Failed to get product string descriptor: %s.", libusb_error_name(ret)); continue; } libusb_close(hdl); prof = NULL; for (j = 0; supported_fx2[j].vid; j++) { if (des.idVendor == supported_fx2[j].vid && des.idProduct == supported_fx2[j].pid && (!supported_fx2[j].usb_manufacturer || !strcmp(manufacturer, supported_fx2[j].usb_manufacturer)) && (!supported_fx2[j].usb_manufacturer || !strcmp(product, supported_fx2[j].usb_product))) { prof = &supported_fx2[j]; break; } } /* Skip if the device was not found. */ if (!prof) continue; devcnt = g_slist_length(drvc->instances); sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING, prof->vendor, prof->model, prof->model_version); if (!sdi) return NULL; sdi->driver = di; /* Fill in channellist according to this device's profile. */ num_logic_channels = prof->dev_caps & DEV_CAPS_16BIT ? 16 : 8; for (j = 0; j < num_logic_channels; j++) { if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE, channel_names[j]))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); } devc = fx2lafw_dev_new(); devc->profile = prof; sdi->priv = devc; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); if (fx2lafw_check_conf_profile(devlist[i])) { /* Already has the firmware, so fix the new address. */ sr_dbg("Found an fx2lafw device."); sdi->status = SR_ST_INACTIVE; sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); } else { if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, prof->firmware) == SR_OK) /* Store when this device's FW was updated. */ devc->fw_updated = g_get_monotonic_time(); else sr_err("Firmware upload failed for " "device %d.", devcnt); sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), 0xff, NULL); } } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int dev_open(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; struct dev_context *devc; int ret; int64_t timediff_us, timediff_ms; devc = sdi->priv; usb = sdi->conn; /* * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS * milliseconds for the FX2 to renumerate. */ ret = SR_ERR; if (devc->fw_updated > 0) { sr_info("Waiting for device to reset."); /* Takes >= 300ms for the FX2 to be gone from the USB bus. */ g_usleep(300 * 1000); timediff_ms = 0; while (timediff_ms < MAX_RENUM_DELAY_MS) { if ((ret = fx2lafw_dev_open(sdi, di)) == SR_OK) break; g_usleep(100 * 1000); timediff_us = g_get_monotonic_time() - devc->fw_updated; timediff_ms = timediff_us / 1000; sr_spew("Waited %" PRIi64 "ms.", timediff_ms); } if (ret != SR_OK) { sr_err("Device failed to renumerate."); return SR_ERR; } sr_info("Device came back after %" PRIi64 "ms.", timediff_ms); } else { sr_info("Firmware upload was not needed."); ret = fx2lafw_dev_open(sdi, di); } if (ret != SR_OK) { sr_err("Unable to open device."); return SR_ERR; } ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); if (ret != 0) { switch (ret) { case LIBUSB_ERROR_BUSY: sr_err("Unable to claim USB interface. Another " "program or driver has already claimed it."); break; case LIBUSB_ERROR_NO_DEVICE: sr_err("Device has been disconnected."); break; default: sr_err("Unable to claim interface: %s.", libusb_error_name(ret)); break; } return SR_ERR; } if (devc->cur_samplerate == 0) { /* Samplerate hasn't been set; default to the slowest one. */ devc->cur_samplerate = samplerates[0]; } return SR_OK; } static int dev_close(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; usb = sdi->conn; if (usb->devhdl == NULL) return SR_ERR; sr_info("fx2lafw: Closing device %d on %d.%d interface %d.", sdi->index, usb->bus, usb->address, USB_INTERFACE); libusb_release_interface(usb->devhdl, USB_INTERFACE); libusb_close(usb->devhdl); usb->devhdl = NULL; sdi->status = SR_ST_INACTIVE; return SR_OK; } static int cleanup(void) { int ret; struct drv_context *drvc; if (!(drvc = di->priv)) return SR_OK; ret = std_dev_clear(di, NULL); g_free(drvc); di->priv = NULL; return ret; } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; struct sr_usb_dev_inst *usb; char str[128]; (void)cg; if (!sdi) return SR_ERR_ARG; devc = sdi->priv; switch (id) { case SR_CONF_CONN: if (!sdi->conn) return SR_ERR_ARG; usb = sdi->conn; if (usb->address == 255) /* Device still needs to re-enumerate after firmware * upload, so we don't know its (future) address. */ return SR_ERR; snprintf(str, 128, "%d.%d", usb->bus, usb->address); *data = g_variant_new_string(str); break; case SR_CONF_LIMIT_SAMPLES: *data = g_variant_new_uint64(devc->limit_samples); break; case SR_CONF_SAMPLERATE: *data = g_variant_new_uint64(devc->cur_samplerate); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; int ret; (void)cg; if (!sdi) return SR_ERR_ARG; if (sdi->status != SR_ST_ACTIVE) return SR_ERR; devc = sdi->priv; ret = SR_OK; switch (id) { case SR_CONF_SAMPLERATE: devc->cur_samplerate = g_variant_get_uint64(data); break; case SR_CONF_LIMIT_SAMPLES: devc->limit_samples = g_variant_get_uint64(data); break; default: ret = SR_ERR_NA; } return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { GVariant *gvar; GVariantBuilder gvb; (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; 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)); g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; case SR_CONF_TRIGGER_TYPE: *data = g_variant_new_string(TRIGGER_TYPE); break; default: return SR_ERR_NA; } return SR_OK; } static int receive_data(int fd, int revents, void *cb_data) { struct timeval tv; struct drv_context *drvc; (void)fd; (void)revents; (void)cb_data; drvc = di->priv; tv.tv_sec = tv.tv_usec = 0; libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv); return TRUE; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct drv_context *drvc; struct sr_usb_dev_inst *usb; struct libusb_transfer *transfer; unsigned int i, timeout, num_transfers; int ret; unsigned char *buf; size_t size; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; drvc = di->priv; devc = sdi->priv; usb = sdi->conn; /* Configures devc->trigger_* and devc->sample_wide */ if (fx2lafw_configure_channels(sdi) != SR_OK) { sr_err("Failed to configure channels."); return SR_ERR; } devc->cb_data = cb_data; devc->sent_samples = 0; devc->acq_aborted = FALSE; devc->empty_transfer_count = 0; timeout = fx2lafw_get_timeout(devc); num_transfers = fx2lafw_get_number_of_transfers(devc); size = fx2lafw_get_buffer_size(devc); devc->submitted_transfers = 0; devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers); if (!devc->transfers) { sr_err("USB transfers malloc failed."); return SR_ERR_MALLOC; } devc->num_transfers = num_transfers; for (i = 0; i < num_transfers; i++) { if (!(buf = g_try_malloc(size))) { sr_err("USB transfer buffer malloc failed."); return SR_ERR_MALLOC; } transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, usb->devhdl, 2 | LIBUSB_ENDPOINT_IN, buf, size, fx2lafw_receive_transfer, devc, timeout); if ((ret = libusb_submit_transfer(transfer)) != 0) { sr_err("Failed to submit transfer: %s.", libusb_error_name(ret)); libusb_free_transfer(transfer); g_free(buf); fx2lafw_abort_acquisition(devc); return SR_ERR; } devc->transfers[i] = transfer; devc->submitted_transfers++; } devc->ctx = drvc->sr_ctx; usb_source_add(devc->ctx, timeout, receive_data, NULL); /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); if ((ret = fx2lafw_command_start_acquisition(sdi)) != SR_OK) { fx2lafw_abort_acquisition(devc); return ret; } return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; fx2lafw_abort_acquisition(sdi->priv); return SR_OK; } SR_PRIV struct sr_dev_driver fx2lafw_driver_info = { .name = "fx2lafw", .longname = "fx2lafw (generic driver for FX2 based LAs)", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/demo/0000755000175000017500000000000012332246734013227 500000000000000libsigrok-0.3.0/hardware/demo/demo.c0000644000175000017500000004772712332246667014265 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2010 Uwe Hermann * Copyright (C) 2011 Olivier Fauchon * Copyright (C) 2012 Alexandru Gagniuc * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #ifdef _WIN32 #include #include #define pipe(fds) _pipe(fds, 4096, _O_BINARY) #endif #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "demo" #define DEFAULT_NUM_LOGIC_CHANNELS 8 #define DEFAULT_NUM_ANALOG_CHANNELS 4 /* The size in bytes of chunks to send through the session bus. */ #define LOGIC_BUFSIZE 4096 /* Size of the analog pattern space per channel. */ #define ANALOG_BUFSIZE 4096 #define ANALOG_AMPLITUDE 25 #define ANALOG_SAMPLES_PER_PERIOD 20 /* Logic patterns we can generate. */ enum { /** * Spells "sigrok" across 8 channels using '0's (with '1's as * "background") when displayed using the 'bits' output format. * The pattern is repeated every 8 channels, shifted to the right * in time by one bit. */ PATTERN_SIGROK, /** Pseudo-random values on all channels. */ PATTERN_RANDOM, /** * Incrementing number across 8 channels. The pattern is repeated * every 8 channels, shifted to the right in time by one bit. */ PATTERN_INC, /** All channels have a low logic state. */ PATTERN_ALL_LOW, /** All channels have a high logic state. */ PATTERN_ALL_HIGH, }; /* Analog patterns we can generate. */ enum { /** * Square wave. */ PATTERN_SQUARE, PATTERN_SINE, PATTERN_TRIANGLE, PATTERN_SAWTOOTH, }; static const char *logic_pattern_str[] = { "sigrok", "random", "incremental", "all-low", "all-high", }; static const char *analog_pattern_str[] = { "square", "sine", "triangle", "sawtooth", }; struct analog_gen { int pattern; float pattern_data[ANALOG_BUFSIZE]; unsigned int num_samples; struct sr_datafeed_analog packet; }; /* Private, per-device-instance driver context. */ struct dev_context { int pipe_fds[2]; GIOChannel *channel; uint64_t cur_samplerate; uint64_t limit_samples; uint64_t limit_msec; uint64_t logic_counter; uint64_t analog_counter; int64_t starttime; uint64_t step; /* Logic */ int32_t num_logic_channels; unsigned int logic_unitsize; /* There is only ever one logic channel group, so its pattern goes here. */ uint8_t logic_pattern; unsigned char logic_data[LOGIC_BUFSIZE]; /* Analog */ int32_t num_analog_channels; GSList *analog_channel_groups; }; static const int32_t scanopts[] = { SR_CONF_NUM_LOGIC_CHANNELS, SR_CONF_NUM_ANALOG_CHANNELS, }; static const int devopts[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_DEMO_DEV, SR_CONF_SAMPLERATE, SR_CONF_LIMIT_SAMPLES, SR_CONF_LIMIT_MSEC, }; static const int devopts_cg[] = { SR_CONF_PATTERN_MODE, }; static const uint64_t samplerates[] = { SR_HZ(1), SR_GHZ(1), SR_HZ(1), }; static uint8_t pattern_sigrok[] = { 0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00, 0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00, 0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; SR_PRIV struct sr_dev_driver demo_driver_info; static struct sr_dev_driver *di = &demo_driver_info; static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data); static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static void generate_analog_pattern(const struct sr_channel_group *cg, uint64_t sample_rate) { struct analog_gen *ag; double t, frequency; float value; unsigned int num_samples, i; int last_end; ag = cg->priv; num_samples = ANALOG_BUFSIZE / sizeof(float); sr_dbg("Generating %s pattern for channel group %s", analog_pattern_str[ag->pattern], cg->name); switch (ag->pattern) { case PATTERN_SQUARE: value = ANALOG_AMPLITUDE; last_end = 0; for (i = 0; i < num_samples; i++) { if (i % 5 == 0) value = -value; if (i % 10 == 0) last_end = i - 1; ag->pattern_data[i] = value; } ag->num_samples = last_end; break; case PATTERN_SINE: frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD; /* Make sure the number of samples we put out is an integer * multiple of our period size */ /* FIXME we actually need only one period. A ringbuffer would be * usefull here.*/ while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0) num_samples--; for (i = 0; i < num_samples; i++) { t = (double) i / (double) sample_rate; ag->pattern_data[i] = ANALOG_AMPLITUDE * sin(2 * M_PI * frequency * t); } ag->num_samples = num_samples; break; case PATTERN_TRIANGLE: frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD; while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0) num_samples--; for (i = 0; i < num_samples; i++) { t = (double) i / (double) sample_rate; ag->pattern_data[i] = (2 * ANALOG_AMPLITUDE / M_PI) * asin(sin(2 * M_PI * frequency * t)); } ag->num_samples = num_samples; break; case PATTERN_SAWTOOTH: frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD; while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0) num_samples--; for (i = 0; i < num_samples; i++) { t = (double) i / (double) sample_rate; ag->pattern_data[i] = 2 * ANALOG_AMPLITUDE * ((t * frequency) - floor(0.5f + t * frequency)); } ag->num_samples = num_samples; break; } } static GSList *scan(GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_channel *ch; struct sr_channel_group *cg; struct sr_config *src; struct analog_gen *ag; GSList *devices, *l; int num_logic_channels, num_analog_channels, pattern, i; char channel_name[16]; drvc = di->priv; num_logic_channels = DEFAULT_NUM_LOGIC_CHANNELS; num_analog_channels = DEFAULT_NUM_ANALOG_CHANNELS; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_NUM_LOGIC_CHANNELS: num_logic_channels = g_variant_get_int32(src->data); break; case SR_CONF_NUM_ANALOG_CHANNELS: num_analog_channels = g_variant_get_int32(src->data); break; } } devices = NULL; sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "Demo device", NULL, NULL); if (!sdi) { sr_err("Device instance creation failed."); return NULL; } sdi->driver = di; if (!(devc = g_try_malloc(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } devc->cur_samplerate = SR_KHZ(200); devc->limit_samples = 0; devc->limit_msec = 0; devc->step = 0; devc->num_logic_channels = num_logic_channels; devc->logic_unitsize = (devc->num_logic_channels + 7) / 8; devc->logic_pattern = PATTERN_SIGROK; devc->num_analog_channels = num_analog_channels; devc->analog_channel_groups = NULL; /* Logic channels, all in one channel group. */ if (!(cg = g_try_malloc(sizeof(struct sr_channel_group)))) return NULL; cg->name = g_strdup("Logic"); cg->channels = NULL; cg->priv = NULL; for (i = 0; i < num_logic_channels; i++) { sprintf(channel_name, "D%d", i); if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); cg->channels = g_slist_append(cg->channels, ch); } sdi->channel_groups = g_slist_append(NULL, cg); /* Analog channels, channel groups and pattern generators. */ pattern = 0; for (i = 0; i < num_analog_channels; i++) { sprintf(channel_name, "A%d", i); if (!(ch = sr_channel_new(i + num_logic_channels, SR_CHANNEL_ANALOG, TRUE, channel_name))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); /* Every analog channel gets its own channel group. */ if (!(cg = g_try_malloc(sizeof(struct sr_channel_group)))) return NULL; cg->name = g_strdup(channel_name); cg->channels = g_slist_append(NULL, ch); /* Every channel group gets a generator struct. */ if (!(ag = g_try_malloc(sizeof(struct analog_gen)))) return NULL; ag->packet.channels = cg->channels; ag->packet.mq = 0; ag->packet.mqflags = 0; ag->packet.unit = SR_UNIT_VOLT; ag->packet.data = ag->pattern_data; ag->pattern = pattern; cg->priv = ag; sdi->channel_groups = g_slist_append(sdi->channel_groups, cg); devc->analog_channel_groups = g_slist_append(devc->analog_channel_groups, cg); if (++pattern == ARRAY_SIZE(analog_pattern_str)) pattern = 0; } sdi->priv = devc; devices = g_slist_append(devices, sdi); drvc->instances = g_slist_append(drvc->instances, sdi); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int dev_open(struct sr_dev_inst *sdi) { sdi->status = SR_ST_ACTIVE; return SR_OK; } static int dev_close(struct sr_dev_inst *sdi) { sdi->status = SR_ST_INACTIVE; return SR_OK; } static int cleanup(void) { return std_dev_clear(di, NULL); } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; struct sr_channel *ch; struct analog_gen *ag; int pattern; if (!sdi) return SR_ERR_ARG; devc = sdi->priv; switch (id) { case SR_CONF_SAMPLERATE: *data = g_variant_new_uint64(devc->cur_samplerate); break; case SR_CONF_LIMIT_SAMPLES: *data = g_variant_new_uint64(devc->limit_samples); break; case SR_CONF_LIMIT_MSEC: *data = g_variant_new_uint64(devc->limit_msec); break; case SR_CONF_PATTERN_MODE: if (!cg) return SR_ERR_CHANNEL_GROUP; ch = cg->channels->data; if (ch->type == SR_CHANNEL_LOGIC) { pattern = devc->logic_pattern; *data = g_variant_new_string(logic_pattern_str[pattern]); } else if (ch->type == SR_CHANNEL_ANALOG) { ag = cg->priv; pattern = ag->pattern; *data = g_variant_new_string(analog_pattern_str[pattern]); } else return SR_ERR_BUG; break; case SR_CONF_NUM_LOGIC_CHANNELS: *data = g_variant_new_int32(devc->num_logic_channels); break; case SR_CONF_NUM_ANALOG_CHANNELS: *data = g_variant_new_int32(devc->num_analog_channels); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; struct analog_gen *ag; struct sr_channel *ch; int pattern, ret; unsigned int i; const char *stropt; devc = sdi->priv; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; ret = SR_OK; switch (id) { case SR_CONF_SAMPLERATE: devc->cur_samplerate = g_variant_get_uint64(data); sr_dbg("Setting samplerate to %" PRIu64, devc->cur_samplerate); break; case SR_CONF_LIMIT_SAMPLES: devc->limit_msec = 0; devc->limit_samples = g_variant_get_uint64(data); sr_dbg("Setting sample limit to %" PRIu64, devc->limit_samples); break; case SR_CONF_LIMIT_MSEC: devc->limit_msec = g_variant_get_uint64(data); devc->limit_samples = 0; sr_dbg("Setting time limit to %" PRIu64"ms", devc->limit_msec); break; case SR_CONF_PATTERN_MODE: if (!cg) return SR_ERR_CHANNEL_GROUP; stropt = g_variant_get_string(data, NULL); ch = cg->channels->data; pattern = -1; if (ch->type == SR_CHANNEL_LOGIC) { for (i = 0; i < ARRAY_SIZE(logic_pattern_str); i++) { if (!strcmp(stropt, logic_pattern_str[i])) { pattern = i; break; } } if (pattern == -1) return SR_ERR_ARG; devc->logic_pattern = pattern; /* Might as well do this now, these are static. */ if (pattern == PATTERN_ALL_LOW) memset(devc->logic_data, 0x00, LOGIC_BUFSIZE); else if (pattern == PATTERN_ALL_HIGH) memset(devc->logic_data, 0xff, LOGIC_BUFSIZE); sr_dbg("Setting logic pattern to %s", logic_pattern_str[pattern]); } else if (ch->type == SR_CHANNEL_ANALOG) { for (i = 0; i < ARRAY_SIZE(analog_pattern_str); i++) { if (!strcmp(stropt, analog_pattern_str[i])) { pattern = i; break; } } if (pattern == -1) return SR_ERR_ARG; sr_dbg("Setting analog pattern for channel group %s to %s", cg->name, analog_pattern_str[pattern]); ag = cg->priv; ag->pattern = pattern; } else return SR_ERR_BUG; break; default: ret = SR_ERR_NA; } return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct sr_channel *ch; GVariant *gvar; GVariantBuilder gvb; (void)sdi; if (key == SR_CONF_SCAN_OPTIONS) { *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t)); return SR_OK; } if (!sdi) return SR_ERR_ARG; if (!cg) { switch (key) { case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, devopts, ARRAY_SIZE(devopts), sizeof(int32_t)); break; 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)); g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar); *data = g_variant_builder_end(&gvb); break; default: return SR_ERR_NA; } } else { ch = cg->channels->data; switch (key) { case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(int32_t)); break; case SR_CONF_PATTERN_MODE: if (ch->type == SR_CHANNEL_LOGIC) *data = g_variant_new_strv(logic_pattern_str, ARRAY_SIZE(logic_pattern_str)); else if (ch->type == SR_CHANNEL_ANALOG) *data = g_variant_new_strv(analog_pattern_str, ARRAY_SIZE(analog_pattern_str)); else return SR_ERR_BUG; break; default: return SR_ERR_NA; } } return SR_OK; } static void logic_generator(struct sr_dev_inst *sdi, uint64_t size) { struct dev_context *devc; uint64_t i, j; uint8_t pat; devc = sdi->priv; switch (devc->logic_pattern) { case PATTERN_SIGROK: memset(devc->logic_data, 0x00, size); for (i = 0; i < size; i += devc->logic_unitsize) { for (j = 0; j < devc->logic_unitsize; j++) { pat = pattern_sigrok[(devc->step + j) % sizeof(pattern_sigrok)] >> 1; devc->logic_data[i + j] = ~pat; } devc->step++; } break; case PATTERN_RANDOM: for (i = 0; i < size; i++) devc->logic_data[i] = (uint8_t)(rand() & 0xff); break; case PATTERN_INC: for (i = 0; i < size; i++) { for (j = 0; j < devc->logic_unitsize; j++) { devc->logic_data[i + j] = devc->step; } devc->step++; } break; case PATTERN_ALL_LOW: case PATTERN_ALL_HIGH: /* These were set when the pattern mode was selected. */ break; default: sr_err("Unknown pattern: %d.", devc->logic_pattern); break; } } /* Callback handling data */ static int prepare_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; struct sr_channel_group *cg; struct analog_gen *ag; GSList *l; uint64_t logic_todo, analog_todo, expected_samplenum, analog_samples, sending_now; int64_t time, elapsed; (void)fd; (void)revents; sdi = cb_data; devc = sdi->priv; /* How many "virtual" samples should we have collected by now? */ time = g_get_monotonic_time(); elapsed = time - devc->starttime; expected_samplenum = elapsed * devc->cur_samplerate / 1000000; /* Of those, how many do we still have to send? */ logic_todo = MIN(expected_samplenum, devc->limit_samples) - devc->logic_counter; analog_todo = MIN(expected_samplenum, devc->limit_samples) - devc->analog_counter; while (logic_todo || analog_todo) { /* Logic */ if (devc->num_logic_channels > 0 && logic_todo > 0) { sending_now = MIN(logic_todo, LOGIC_BUFSIZE / devc->logic_unitsize); logic_generator(sdi, sending_now * devc->logic_unitsize); packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = sending_now * devc->logic_unitsize; logic.unitsize = devc->logic_unitsize; logic.data = devc->logic_data; sr_session_send(sdi, &packet); logic_todo -= sending_now; devc->logic_counter += sending_now; } /* Analog, one channel at a time */ if (devc->num_analog_channels > 0 && analog_todo > 0) { sending_now = 0; for (l = devc->analog_channel_groups; l; l = l->next) { cg = l->data; ag = cg->priv; packet.type = SR_DF_ANALOG; packet.payload = &ag->packet; /* FIXME we should make sure we output a whole * period of data before we send out again the * beginning of our buffer. A ring buffer would * help here as well */ analog_samples = MIN(analog_todo, ag->num_samples); /* Whichever channel group gets there first. */ sending_now = MAX(sending_now, analog_samples); ag->packet.num_samples = analog_samples; sr_session_send(sdi, &packet); } analog_todo -= sending_now; devc->analog_counter += sending_now; } } if (devc->logic_counter >= devc->limit_samples && devc->analog_counter >= devc->limit_samples) { sr_dbg("Requested number of samples reached."); dev_acquisition_stop(sdi, cb_data); return TRUE; } return TRUE; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { GSList *l; struct dev_context *devc; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; if (devc->limit_samples == 0) return SR_ERR; devc->logic_counter = devc->analog_counter = 0; /* * Setting two channels connected by a pipe is a remnant from when the * demo driver generated data in a thread, and collected and sent the * data in the main program loop. * They are kept here because it provides a convenient way of setting * up a timeout-based polling mechanism. */ if (pipe(devc->pipe_fds)) { sr_err("%s: pipe() failed", __func__); return SR_ERR; } for (l = devc->analog_channel_groups; l; l = l->next) { generate_analog_pattern(l->data, devc->cur_samplerate); } devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]); g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL); /* Set channel encoding to binary (default is UTF-8). */ g_io_channel_set_encoding(devc->channel, NULL, NULL); /* Make channels to unbuffered. */ g_io_channel_set_buffered(devc->channel, FALSE); sr_session_source_add_channel(devc->channel, G_IO_IN | G_IO_ERR, 40, prepare_data, (void *)sdi); /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* We use this timestamp to decide how many more samples to send. */ devc->starttime = g_get_monotonic_time(); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct sr_datafeed_packet packet; (void)cb_data; devc = sdi->priv; sr_dbg("Stopping acquisition."); sr_session_source_remove_channel(devc->channel); g_io_channel_shutdown(devc->channel, FALSE, NULL); g_io_channel_unref(devc->channel); devc->channel = NULL; /* Send last packet. */ packet.type = SR_DF_END; sr_session_send(sdi, &packet); return SR_OK; } SR_PRIV struct sr_dev_driver demo_driver_info = { .name = "demo", .longname = "Demo driver and pattern generator", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/sysclk-lwla/0000755000175000017500000000000012332246734014550 500000000000000libsigrok-0.3.0/hardware/sysclk-lwla/lwla.h0000644000175000017500000000730512332246667015612 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2014 Daniel Elstner * * 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 . */ #ifndef LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H #define LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H #include "libsigrok.h" #include #include #include struct sr_usb_dev_inst; /* Rotate argument n bits to the left. * This construct is an idiom recognized by GCC as bit rotation. */ #define LROTATE(a, n) (((a) << (n)) | ((a) >> (CHAR_BIT * sizeof(a) - (n)))) /* Convert 16-bit little endian LWLA protocol word to machine word order. */ #define LWLA_TO_UINT16(val) GUINT16_FROM_LE(val) /* Convert 32-bit mixed endian LWLA protocol word to machine word order. */ #define LWLA_TO_UINT32(val) LROTATE(GUINT32_FROM_LE(val), 16) /* Convert 16-bit argument to LWLA protocol word. */ #define LWLA_WORD(val) GUINT16_TO_LE(val) /* Extract 16-bit units in mixed endian order from 32/64-bit value. */ #define LWLA_WORD_0(val) GUINT16_TO_LE(((val) >> 16) & 0xFFFF) #define LWLA_WORD_1(val) GUINT16_TO_LE((val) & 0xFFFF) #define LWLA_WORD_2(val) GUINT16_TO_LE(((val) >> 48) & 0xFFFF) #define LWLA_WORD_3(val) GUINT16_TO_LE(((val) >> 32) & 0xFFFF) /** USB device end points. */ enum { EP_COMMAND = 2, EP_BITSTREAM = 4, EP_REPLY = 6 | LIBUSB_ENDPOINT_IN }; /** LWLA protocol command ID codes. */ enum { CMD_READ_REG = 1, CMD_WRITE_REG = 2, CMD_READ_MEM = 6, CMD_CAP_SETUP = 7, CMD_CAP_STATUS = 8, }; /** LWLA capture state flags. */ enum { STATUS_CAPTURING = 1 << 1, STATUS_TRIGGERED = 1 << 4, STATUS_MEM_AVAIL = 1 << 5, STATUS_FLAG_MASK = 0x3F }; /** LWLA register addresses. */ enum { REG_MEM_CTRL2 = 0x1074, /* capture buffer control ??? */ REG_MEM_FILL = 0x1078, /* capture buffer fill level */ REG_MEM_CTRL4 = 0x107C, /* capture buffer control ??? */ REG_DIV_BYPASS = 0x1094, /* bypass clock divider flag */ REG_CMD_CTRL1 = 0x10B0, /* command control ??? */ REG_CMD_CTRL2 = 0x10B4, /* command control ??? */ REG_CMD_CTRL3 = 0x10B8, /* command control ??? */ REG_CMD_CTRL4 = 0x10BC, /* command control ??? */ REG_FREQ_CH1 = 0x10C0, /* channel 1 live frequency */ REG_FREQ_CH2 = 0x10C4, /* channel 2 live frequency */ REG_FREQ_CH3 = 0x10C8, /* channel 3 live frequency */ REG_FREQ_CH4 = 0x10CC, /* channel 4 live frequency */ }; /** Register/value pair. */ struct regval_pair { unsigned int reg; unsigned int val; }; SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb, const char *basename); SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb, const uint16_t *command, int cmd_len); SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb, uint32_t *reply, int reply_len, int expect_len); SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb, uint16_t reg, uint32_t *value); SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb, uint16_t reg, uint32_t value); SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb, const struct regval_pair *regvals, int count); #endif /* !LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H */ libsigrok-0.3.0/hardware/sysclk-lwla/lwla.c0000644000175000017500000001401512332246667015601 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2014 Daniel Elstner * * 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 . */ #include "lwla.h" #include "protocol.h" #include "libsigrok-internal.h" #include #include #define BITSTREAM_MAX_SIZE 262144 /* bitstream size limit for safety */ #define BITSTREAM_HEADER_SIZE 4 /* transfer header size in bytes */ /* Load a bitstream file into memory. Returns a newly allocated array * consisting of a 32-bit length field followed by the bitstream data. */ static unsigned char *load_bitstream_file(const char *filename, int *length_p) { GStatBuf statbuf; FILE *file; unsigned char *stream; size_t length, count; /* Retrieve and validate the file size. */ if (g_stat(filename, &statbuf) < 0) { sr_err("Failed to access bitstream file: %s.", g_strerror(errno)); return NULL; } if (!S_ISREG(statbuf.st_mode)) { sr_err("Bitstream is not a regular file."); return NULL; } if (statbuf.st_size <= 0 || statbuf.st_size > BITSTREAM_MAX_SIZE) { sr_err("Refusing to load bitstream of unreasonable size " "(%" PRIu64 " bytes).", (uint64_t)statbuf.st_size); return NULL; } /* The message length includes the 4-byte header. */ length = BITSTREAM_HEADER_SIZE + statbuf.st_size; stream = g_try_malloc(length); if (!stream) { sr_err("Failed to allocate bitstream buffer."); return NULL; } file = g_fopen(filename, "rb"); if (!file) { sr_err("Failed to open bitstream file: %s.", g_strerror(errno)); g_free(stream); return NULL; } /* Write the message length header. */ *(uint32_t *)stream = GUINT32_TO_BE(length); count = fread(stream + BITSTREAM_HEADER_SIZE, length - BITSTREAM_HEADER_SIZE, 1, file); if (count != 1) { sr_err("Failed to read bitstream file: %s.", g_strerror(errno)); fclose(file); g_free(stream); return NULL; } fclose(file); *length_p = length; return stream; } /* Load a Raw Binary File (.rbf) from the firmware directory and transfer * it to the device. */ SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb, const char *basename) { char *filename; unsigned char *stream; int ret; int length; int xfer_len; if (!usb || !basename) return SR_ERR_BUG; filename = g_build_filename(FIRMWARE_DIR, basename, NULL); sr_info("Downloading FPGA bitstream at '%s'.", filename); stream = load_bitstream_file(filename, &length); g_free(filename); if (!stream) return SR_ERR; /* Transfer the entire bitstream in one URB. */ ret = libusb_bulk_transfer(usb->devhdl, EP_BITSTREAM, stream, length, &xfer_len, USB_TIMEOUT); g_free(stream); if (ret != 0) { sr_err("Failed to transfer bitstream: %s.", libusb_error_name(ret)); return SR_ERR; } if (xfer_len != length) { sr_err("Failed to transfer bitstream: incorrect length " "%d != %d.", xfer_len, length); return SR_ERR; } sr_info("FPGA bitstream download of %d bytes done.", xfer_len); /* This delay appears to be necessary for reliable operation. */ g_usleep(30000); return SR_OK; } SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb, const uint16_t *command, int cmd_len) { int ret; int xfer_len; if (!usb || !command || cmd_len <= 0) return SR_ERR_BUG; xfer_len = 0; ret = libusb_bulk_transfer(usb->devhdl, EP_COMMAND, (unsigned char *)command, cmd_len * 2, &xfer_len, USB_TIMEOUT); if (ret != 0) { sr_dbg("Failed to send command %d: %s.", LWLA_TO_UINT16(command[0]), libusb_error_name(ret)); return SR_ERR; } if (xfer_len != cmd_len * 2) { sr_dbg("Failed to send command %d: incorrect length %d != %d.", LWLA_TO_UINT16(command[0]), xfer_len, cmd_len * 2); return SR_ERR; } return SR_OK; } SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb, uint32_t *reply, int reply_len, int expect_len) { int ret; int xfer_len; if (!usb || !reply || reply_len <= 0) return SR_ERR_BUG; xfer_len = 0; ret = libusb_bulk_transfer(usb->devhdl, EP_REPLY, (unsigned char *)reply, reply_len * 4, &xfer_len, USB_TIMEOUT); if (ret != 0) { sr_dbg("Failed to receive reply: %s.", libusb_error_name(ret)); return SR_ERR; } if (xfer_len != expect_len * 4) { sr_dbg("Failed to receive reply: incorrect length %d != %d.", xfer_len, expect_len * 4); return SR_ERR; } return SR_OK; } SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb, uint16_t reg, uint32_t *value) { int ret; uint16_t command[2]; uint32_t reply[128]; /* full EP buffer to avoid overflows */ command[0] = LWLA_WORD(CMD_READ_REG); command[1] = LWLA_WORD(reg); ret = lwla_send_command(usb, command, G_N_ELEMENTS(command)); if (ret != SR_OK) return ret; ret = lwla_receive_reply(usb, reply, G_N_ELEMENTS(reply), 1); if (ret == SR_OK) *value = LWLA_TO_UINT32(reply[0]); return ret; } SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb, uint16_t reg, uint32_t value) { uint16_t command[4]; command[0] = LWLA_WORD(CMD_WRITE_REG); command[1] = LWLA_WORD(reg); command[2] = LWLA_WORD_0(value); command[3] = LWLA_WORD_1(value); return lwla_send_command(usb, command, G_N_ELEMENTS(command)); } SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb, const struct regval_pair *regvals, int count) { int i; int ret; ret = SR_OK; for (i = 0; i < count; ++i) { ret = lwla_write_reg(usb, regvals[i].reg, regvals[i].val); if (ret != SR_OK) break; } return ret; } libsigrok-0.3.0/hardware/sysclk-lwla/protocol.h0000644000175000017500000001601712332246667016514 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2014 Daniel Elstner * * 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 . */ #ifndef LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H #define LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H #define LOG_PREFIX "sysclk-lwla" #include "lwla.h" #include "libsigrok.h" #include "libsigrok-internal.h" #include #include /* For now, only the LWLA1034 is supported. */ #define VENDOR_NAME "SysClk" #define MODEL_NAME "LWLA1034" #define USB_VID_PID "2961.6689" #define USB_INTERFACE 0 #define USB_TIMEOUT 3000 /* ms */ #define NUM_CHANNELS 34 #define TRIGGER_TYPES "01fr" /* Bit mask covering all 34 channels. */ #define ALL_CHANNELS_MASK (((uint64_t)1 << NUM_CHANNELS) - 1) /** Unit and packet size for the sigrok logic datafeed. */ #define UNIT_SIZE ((NUM_CHANNELS + 7) / 8) #define PACKET_LENGTH 10000 /* units */ /** Size of the acquisition buffer in device memory units. */ #define MEMORY_DEPTH (256 * 1024) /* 256k x 36 bit */ /** Number of device memory units (36 bit) to read at a time. Slices of 8 * consecutive 36-bit words are mapped to 9 32-bit words each, so the chunk * length should be a multiple of 8 to ensure alignment to slice boundaries. * * Experimentation has shown that reading chunks larger than about 1024 bytes * is unreliable. The threshold seems to relate to the buffer size on the FX2 * USB chip: The configured endpoint buffer size is 512, and with double or * triple buffering enabled a multiple of 512 bytes can be kept in fly. * * The vendor software limits reads to 120 words (15 slices, 540 bytes) at * a time. So far, it appears safe to increase this to 224 words (28 slices, * 1008 bytes), thus making the most of two 512 byte buffers. */ #define READ_CHUNK_LEN (28 * 8) /** Calculate the required buffer size in 32-bit units for reading a given * number of device memory words. Rounded to a multiple of 8 device words. */ #define LWLA1034_MEMBUF_LEN(count) (((count) + 7) / 8 * 9) /** Maximum number of 16-bit words sent at a time during acquisition. * Used for allocating the libusb transfer buffer. */ #define MAX_ACQ_SEND_WORDS 8 /* 5 for memory read request plus stuffing */ /** Maximum number of 32-bit words received at a time during acquisition. * Round to the next multiple of the endpoint buffer size to avoid nasty * transfer overflow conditions on hiccups. */ #define MAX_ACQ_RECV_LEN ((READ_CHUNK_LEN / 8 * 9 + 127) / 128 * 128) /** Maximum length of a register write sequence. */ #define MAX_REG_WRITE_SEQ_LEN 5 /** Default configured samplerate. */ #define DEFAULT_SAMPLERATE SR_MHZ(125) /** Maximum configurable sample count limit. */ #define MAX_LIMIT_SAMPLES (UINT64_C(1) << 48) /** Maximum configurable capture duration in milliseconds. */ #define MAX_LIMIT_MSEC (UINT64_C(1) << 32) /** LWLA1034 FPGA clock configurations. */ enum clock_config { CONF_CLOCK_NONE, CONF_CLOCK_INT, CONF_CLOCK_EXT_RISE, CONF_CLOCK_EXT_FALL, }; /** Available clock sources. */ enum clock_source { CLOCK_INTERNAL, CLOCK_EXT_CLK, }; /** Available trigger sources. */ enum trigger_source { TRIGGER_CHANNELS = 0, TRIGGER_EXT_TRG, }; /** Available edge choices for the external clock and trigger inputs. */ enum signal_edge { EDGE_POSITIVE = 0, EDGE_NEGATIVE, }; /** LWLA device states. */ enum device_state { STATE_IDLE = 0, STATE_START_CAPTURE, STATE_STATUS_WAIT, STATE_STATUS_REQUEST, STATE_STATUS_RESPONSE, STATE_STOP_CAPTURE, STATE_LENGTH_REQUEST, STATE_LENGTH_RESPONSE, STATE_READ_PREPARE, STATE_READ_REQUEST, STATE_READ_RESPONSE, STATE_READ_END, }; /** LWLA run-length encoding states. */ enum rle_state { RLE_STATE_DATA, RLE_STATE_LEN }; /** LWLA sample acquisition and decompression state. */ struct acquisition_state { uint64_t sample; uint64_t run_len; /** Maximum number of samples to process. */ uint64_t samples_max; /** Number of samples sent to the session bus. */ uint64_t samples_done; /** Maximum duration of capture, in milliseconds. */ uint64_t duration_max; /** Running capture duration since trigger event. */ uint64_t duration_now; /** Capture memory fill level. */ size_t mem_addr_fill; size_t mem_addr_done; size_t mem_addr_next; size_t mem_addr_stop; size_t out_index; struct libusb_transfer *xfer_in; struct libusb_transfer *xfer_out; unsigned int capture_flags; enum rle_state rle; /** Whether to bypass the clock divider. */ gboolean bypass_clockdiv; /* Payload data buffers for incoming and outgoing transfers. */ uint32_t xfer_buf_in[MAX_ACQ_RECV_LEN]; uint16_t xfer_buf_out[MAX_ACQ_SEND_WORDS]; /* Payload buffer for sigrok logic packets. */ uint8_t out_packet[PACKET_LENGTH * UNIT_SIZE]; }; /** Private, per-device-instance driver context. */ struct dev_context { /** The samplerate selected by the user. */ uint64_t samplerate; /** The maximimum sampling duration, in milliseconds. */ uint64_t limit_msec; /** The maximimum number of samples to acquire. */ uint64_t limit_samples; /** Channels to use. */ uint64_t channel_mask; uint64_t trigger_mask; uint64_t trigger_edge_mask; uint64_t trigger_values; struct acquisition_state *acquisition; struct regval_pair reg_write_seq[MAX_REG_WRITE_SEQ_LEN]; int reg_write_pos; int reg_write_len; enum device_state state; /** The currently active clock configuration of the device. */ enum clock_config cur_clock_config; /** Clock source configuration setting. */ enum clock_source cfg_clock_source; /** Clock edge configuration setting. */ enum signal_edge cfg_clock_edge; /** Trigger source configuration setting. */ enum trigger_source cfg_trigger_source; /** Trigger slope configuration setting. */ enum signal_edge cfg_trigger_slope; /* Indicates that stopping the acquisition is currently in progress. */ gboolean stopping_in_progress; /* Indicates whether a transfer failed. */ gboolean transfer_error; }; SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void); SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq); SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi); SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi); SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi); SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi); SR_PRIV int lwla_abort_acquisition(const struct sr_dev_inst *sdi); SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data); #endif /* !LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H */ libsigrok-0.3.0/hardware/sysclk-lwla/protocol.c0000644000175000017500000006300112332246667016502 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2014 Daniel Elstner * * 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 . */ #include "protocol.h" #include /* Bit mask for the RLE repeat-count-follows flag. */ #define RLE_FLAG_LEN_FOLLOWS ((uint64_t)1 << 35) /* Start address of capture status memory area to read. */ #define CAP_STAT_ADDR 5 /* Number of 64-bit words read from the capture status memory. */ #define CAP_STAT_LEN 5 /* The bitstream filenames are indexed by the clock_config enumeration. */ static const char bitstream_map[][32] = { "sysclk-lwla1034-off.rbf", "sysclk-lwla1034-int.rbf", "sysclk-lwla1034-extpos.rbf", "sysclk-lwla1034-extneg.rbf", }; /* Submit an already filled-in USB transfer. */ static int submit_transfer(struct dev_context *devc, struct libusb_transfer *xfer) { int ret; ret = libusb_submit_transfer(xfer); if (ret != 0) { sr_err("Submit transfer failed: %s.", libusb_error_name(ret)); devc->transfer_error = TRUE; return SR_ERR; } return SR_OK; } /* Set up the LWLA in preparation for an acquisition session. */ static int capture_setup(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct acquisition_state *acq; uint64_t divider_count; uint64_t trigger_mask; uint64_t memory_limit; uint16_t command[3 + 10*4]; devc = sdi->priv; acq = devc->acquisition; command[0] = LWLA_WORD(CMD_CAP_SETUP); command[1] = LWLA_WORD(0); /* address */ command[2] = LWLA_WORD(10); /* length */ command[3] = LWLA_WORD_0(devc->channel_mask); command[4] = LWLA_WORD_1(devc->channel_mask); command[5] = LWLA_WORD_2(devc->channel_mask); command[6] = LWLA_WORD_3(devc->channel_mask); /* Set the clock divide counter maximum for samplerates of up to * 100 MHz. At the highest samplerate of 125 MHz the clock divider * is bypassed. */ if (!acq->bypass_clockdiv && devc->samplerate > 0) divider_count = SR_MHZ(100) / devc->samplerate - 1; else divider_count = 0; command[7] = LWLA_WORD_0(divider_count); command[8] = LWLA_WORD_1(divider_count); command[9] = LWLA_WORD_2(divider_count); command[10] = LWLA_WORD_3(divider_count); command[11] = LWLA_WORD_0(devc->trigger_values); command[12] = LWLA_WORD_1(devc->trigger_values); command[13] = LWLA_WORD_2(devc->trigger_values); command[14] = LWLA_WORD_3(devc->trigger_values); command[15] = LWLA_WORD_0(devc->trigger_edge_mask); command[16] = LWLA_WORD_1(devc->trigger_edge_mask); command[17] = LWLA_WORD_2(devc->trigger_edge_mask); command[18] = LWLA_WORD_3(devc->trigger_edge_mask); trigger_mask = devc->trigger_mask; /* Set bits to select external TRG input edge. */ if (devc->cfg_trigger_source == TRIGGER_EXT_TRG) switch (devc->cfg_trigger_slope) { case EDGE_POSITIVE: trigger_mask |= (uint64_t)1 << 35; break; case EDGE_NEGATIVE: trigger_mask |= (uint64_t)1 << 34; break; } command[19] = LWLA_WORD_0(trigger_mask); command[20] = LWLA_WORD_1(trigger_mask); command[21] = LWLA_WORD_2(trigger_mask); command[22] = LWLA_WORD_3(trigger_mask); /* Set the capture memory full threshold. This is slightly less * than the actual maximum, most likely in order to compensate for * pipeline latency. */ memory_limit = MEMORY_DEPTH - 16; command[23] = LWLA_WORD_0(memory_limit); command[24] = LWLA_WORD_1(memory_limit); command[25] = LWLA_WORD_2(memory_limit); command[26] = LWLA_WORD_3(memory_limit); /* Fill remaining 64-bit words with zeroes. */ memset(&command[27], 0, 16 * sizeof(uint16_t)); return lwla_send_command(sdi->conn, command, G_N_ELEMENTS(command)); } /* Issue a register write command as an asynchronous USB transfer. */ static int issue_write_reg(const struct sr_dev_inst *sdi, unsigned int reg, unsigned int value) { struct dev_context *devc; struct acquisition_state *acq; devc = sdi->priv; acq = devc->acquisition; acq->xfer_buf_out[0] = LWLA_WORD(CMD_WRITE_REG); acq->xfer_buf_out[1] = LWLA_WORD(reg); acq->xfer_buf_out[2] = LWLA_WORD_0(value); acq->xfer_buf_out[3] = LWLA_WORD_1(value); acq->xfer_out->length = 4 * sizeof(uint16_t); return submit_transfer(devc, acq->xfer_out); } /* Issue a register write command as an asynchronous USB transfer for the * next register/value pair of the currently active register write sequence. */ static int issue_next_write_reg(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct regval_pair *regval; int ret; devc = sdi->priv; if (devc->reg_write_pos >= devc->reg_write_len) { sr_err("Already written all registers in sequence."); return SR_ERR_BUG; } regval = &devc->reg_write_seq[devc->reg_write_pos]; ret = issue_write_reg(sdi, regval->reg, regval->val); if (ret != SR_OK) return ret; ++devc->reg_write_pos; return SR_OK; } /* Issue a capture status request as an asynchronous USB transfer. */ static void request_capture_status(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct acquisition_state *acq; devc = sdi->priv; acq = devc->acquisition; acq->xfer_buf_out[0] = LWLA_WORD(CMD_CAP_STATUS); acq->xfer_buf_out[1] = LWLA_WORD(CAP_STAT_ADDR); acq->xfer_buf_out[2] = LWLA_WORD(CAP_STAT_LEN); acq->xfer_out->length = 3 * sizeof(uint16_t); if (submit_transfer(devc, acq->xfer_out) == SR_OK) devc->state = STATE_STATUS_REQUEST; } /* Issue a request for the capture buffer fill level as * an asynchronous USB transfer. */ static void request_capture_length(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct acquisition_state *acq; devc = sdi->priv; acq = devc->acquisition; acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_REG); acq->xfer_buf_out[1] = LWLA_WORD(REG_MEM_FILL); acq->xfer_out->length = 2 * sizeof(uint16_t); if (submit_transfer(devc, acq->xfer_out) == SR_OK) devc->state = STATE_LENGTH_REQUEST; } /* Initiate the capture memory read operation: Reset the acquisition state * and start a sequence of register writes in order to set up the device for * reading from the capture buffer. */ static void issue_read_start(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct acquisition_state *acq; struct regval_pair *regvals; devc = sdi->priv; acq = devc->acquisition; /* Reset RLE state. */ acq->rle = RLE_STATE_DATA; acq->sample = 0; acq->run_len = 0; acq->samples_done = 0; /* For some reason, the start address is 4 rather than 0. */ acq->mem_addr_done = 4; acq->mem_addr_next = 4; acq->mem_addr_stop = acq->mem_addr_fill; /* Sample position in the packet output buffer. */ acq->out_index = 0; regvals = devc->reg_write_seq; regvals[0].reg = REG_DIV_BYPASS; regvals[0].val = 1; regvals[1].reg = REG_MEM_CTRL2; regvals[1].val = 2; regvals[2].reg = REG_MEM_CTRL4; regvals[2].val = 4; devc->reg_write_pos = 0; devc->reg_write_len = 3; if (issue_next_write_reg(sdi) == SR_OK) devc->state = STATE_READ_PREPARE; } /* Issue a command as an asynchronous USB transfer which returns the device * to normal state after a read operation. Sets a new device context state * on success. */ static void issue_read_end(const struct sr_dev_inst *sdi) { struct dev_context *devc; devc = sdi->priv; if (issue_write_reg(sdi, REG_DIV_BYPASS, 0) == SR_OK) devc->state = STATE_READ_END; } /* Decode an incoming reponse to a buffer fill level request and act on it * as appropriate. Note that this function changes the device context state. */ static void process_capture_length(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct acquisition_state *acq; devc = sdi->priv; acq = devc->acquisition; if (acq->xfer_in->actual_length != 4) { sr_err("Received size %d doesn't match expected size 4.", acq->xfer_in->actual_length); devc->transfer_error = TRUE; return; } acq->mem_addr_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]); sr_dbg("%zu words in capture buffer.", acq->mem_addr_fill); if (acq->mem_addr_fill > 0 && sdi->status == SR_ST_ACTIVE) issue_read_start(sdi); else issue_read_end(sdi); } /* Initiate a sequence of register write commands with the effect of * cancelling a running capture operation. This sets a new device state * if issuing the first command succeeds. */ static void issue_stop_capture(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct regval_pair *regvals; devc = sdi->priv; if (devc->stopping_in_progress) return; regvals = devc->reg_write_seq; regvals[0].reg = REG_CMD_CTRL2; regvals[0].val = 10; regvals[1].reg = REG_CMD_CTRL3; regvals[1].val = 0; regvals[2].reg = REG_CMD_CTRL4; regvals[2].val = 0; regvals[3].reg = REG_CMD_CTRL1; regvals[3].val = 0; regvals[4].reg = REG_DIV_BYPASS; regvals[4].val = 0; devc->reg_write_pos = 0; devc->reg_write_len = 5; if (issue_next_write_reg(sdi) == SR_OK) { devc->stopping_in_progress = TRUE; devc->state = STATE_STOP_CAPTURE; } } /* Decode an incoming capture status reponse and act on it as appropriate. * Note that this function changes the device state. */ static void process_capture_status(const struct sr_dev_inst *sdi) { uint64_t duration; struct dev_context *devc; struct acquisition_state *acq; unsigned int mem_fill; unsigned int flags; devc = sdi->priv; acq = devc->acquisition; if (acq->xfer_in->actual_length != CAP_STAT_LEN * 8) { sr_err("Received size %d doesn't match expected size %d.", acq->xfer_in->actual_length, CAP_STAT_LEN * 8); devc->transfer_error = TRUE; return; } /* TODO: Find out the actual bit width of these fields as stored * in the FPGA. These fields are definitely less than 64 bit wide * internally, and the unused bits occasionally even contain garbage. */ mem_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]); duration = LWLA_TO_UINT32(acq->xfer_buf_in[4]); flags = LWLA_TO_UINT32(acq->xfer_buf_in[8]) & STATUS_FLAG_MASK; /* The LWLA1034 runs at 125 MHz if the clock divider is bypassed. * However, the time base used for the duration is apparently not * adjusted for this "boost" mode. Whereas normally the duration * unit is 1 ms, it is 0.8 ms when the clock divider is bypassed. * As 0.8 = 100 MHz / 125 MHz, it seems that the internal cycle * counter period is the same as at the 100 MHz setting. */ if (acq->bypass_clockdiv) acq->duration_now = duration * 4 / 5; else acq->duration_now = duration; sr_spew("Captured %u words, %" PRIu64 " ms, flags 0x%02X.", mem_fill, acq->duration_now, flags); if ((flags & STATUS_TRIGGERED) > (acq->capture_flags & STATUS_TRIGGERED)) sr_info("Capture triggered."); acq->capture_flags = flags; if (acq->duration_now >= acq->duration_max) { sr_dbg("Time limit reached, stopping capture."); issue_stop_capture(sdi); return; } devc->state = STATE_STATUS_WAIT; if ((acq->capture_flags & STATUS_TRIGGERED) == 0) { sr_spew("Waiting for trigger."); } else if ((acq->capture_flags & STATUS_MEM_AVAIL) == 0) { sr_dbg("Capture memory filled."); request_capture_length(sdi); } else if ((acq->capture_flags & STATUS_CAPTURING) != 0) { sr_spew("Sampling in progress."); } } /* Issue a capture buffer read request as an asynchronous USB transfer. * The address and size of the memory area to read are derived from the * current acquisition state. */ static void request_read_mem(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct acquisition_state *acq; size_t count; devc = sdi->priv; acq = devc->acquisition; if (acq->mem_addr_next >= acq->mem_addr_stop) return; /* Always read a multiple of 8 device words. */ count = (acq->mem_addr_stop - acq->mem_addr_next + 7) / 8 * 8; count = MIN(count, READ_CHUNK_LEN); acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_MEM); acq->xfer_buf_out[1] = LWLA_WORD_0(acq->mem_addr_next); acq->xfer_buf_out[2] = LWLA_WORD_1(acq->mem_addr_next); acq->xfer_buf_out[3] = LWLA_WORD_0(count); acq->xfer_buf_out[4] = LWLA_WORD_1(count); acq->xfer_out->length = 5 * sizeof(uint16_t); if (submit_transfer(devc, acq->xfer_out) == SR_OK) { acq->mem_addr_next += count; devc->state = STATE_READ_REQUEST; } } /* Demangle and decompress incoming sample data from the capture buffer. * The data chunk is taken from the acquisition state, and is expected to * contain a multiple of 8 device words. * All data currently in the acquisition buffer will be processed. Packets * of decoded samples are sent off to the session bus whenever the output * buffer becomes full while decoding. */ static int process_sample_data(const struct sr_dev_inst *sdi) { uint64_t sample; uint64_t high_nibbles; uint64_t word; struct dev_context *devc; struct acquisition_state *acq; uint8_t *out_p; uint32_t *slice; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; size_t expect_len; size_t actual_len; size_t out_max_samples; size_t out_run_samples; size_t ri; size_t in_words_left; size_t si; devc = sdi->priv; acq = devc->acquisition; if (acq->mem_addr_done >= acq->mem_addr_stop || acq->samples_done >= acq->samples_max) return SR_OK; in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done, READ_CHUNK_LEN); expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint32_t); actual_len = acq->xfer_in->actual_length; if (actual_len != expect_len) { sr_err("Received size %zu does not match expected size %zu.", actual_len, expect_len); devc->transfer_error = TRUE; return SR_ERR; } acq->mem_addr_done += in_words_left; /* Prepare session packet. */ packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.unitsize = UNIT_SIZE; logic.data = acq->out_packet; slice = acq->xfer_buf_in; si = 0; /* word index within slice */ for (;;) { /* Calculate number of samples to write into packet. */ out_max_samples = MIN(acq->samples_max - acq->samples_done, PACKET_LENGTH - acq->out_index); out_run_samples = MIN(acq->run_len, out_max_samples); /* Expand run-length samples into session packet. */ sample = acq->sample; out_p = &acq->out_packet[acq->out_index * UNIT_SIZE]; for (ri = 0; ri < out_run_samples; ++ri) { out_p[0] = sample & 0xFF; out_p[1] = (sample >> 8) & 0xFF; out_p[2] = (sample >> 16) & 0xFF; out_p[3] = (sample >> 24) & 0xFF; out_p[4] = (sample >> 32) & 0xFF; out_p += UNIT_SIZE; } acq->run_len -= out_run_samples; acq->out_index += out_run_samples; acq->samples_done += out_run_samples; /* Packet full or sample count limit reached? */ if (out_run_samples == out_max_samples) { logic.length = acq->out_index * UNIT_SIZE; sr_session_send(sdi, &packet); acq->out_index = 0; if (acq->samples_done >= acq->samples_max) return SR_OK; /* sample limit reached */ if (acq->run_len > 0) continue; /* need another packet */ } if (in_words_left == 0) break; /* done with current chunk */ /* Now work on the current slice. */ high_nibbles = LWLA_TO_UINT32(slice[8]); word = LWLA_TO_UINT32(slice[si]); word |= (high_nibbles << (4 * si + 4)) & ((uint64_t)0xF << 32); if (acq->rle == RLE_STATE_DATA) { acq->sample = word & ALL_CHANNELS_MASK; acq->run_len = ((word >> NUM_CHANNELS) & 1) + 1; if (word & RLE_FLAG_LEN_FOLLOWS) acq->rle = RLE_STATE_LEN; } else { acq->run_len += word << 1; acq->rle = RLE_STATE_DATA; } /* Move to next word. */ si = (si + 1) % 8; if (si == 0) slice += 9; --in_words_left; } /* Send out partially filled packet if this was the last chunk. */ if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_index > 0) { logic.length = acq->out_index * UNIT_SIZE; sr_session_send(sdi, &packet); acq->out_index = 0; } return SR_OK; } /* Finish an acquisition session. This sends the end packet to the session * bus and removes the listener for asynchronous USB transfers. */ static void end_acquisition(struct sr_dev_inst *sdi) { struct drv_context *drvc; struct dev_context *devc; struct sr_datafeed_packet packet; drvc = sdi->driver->priv; devc = sdi->priv; if (devc->state == STATE_IDLE) return; devc->state = STATE_IDLE; /* Remove USB file descriptors from polling. */ usb_source_remove(drvc->sr_ctx); packet.type = SR_DF_END; sr_session_send(sdi, &packet); lwla_free_acquisition_state(devc->acquisition); devc->acquisition = NULL; sdi->status = SR_ST_ACTIVE; } /* USB output transfer completion callback. */ static void receive_transfer_out(struct libusb_transfer *transfer) { struct sr_dev_inst *sdi; struct dev_context *devc; sdi = transfer->user_data; devc = sdi->priv; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { sr_err("Transfer to device failed: %d.", transfer->status); devc->transfer_error = TRUE; return; } if (devc->reg_write_pos < devc->reg_write_len) { issue_next_write_reg(sdi); } else { switch (devc->state) { case STATE_START_CAPTURE: devc->state = STATE_STATUS_WAIT; break; case STATE_STATUS_REQUEST: devc->state = STATE_STATUS_RESPONSE; submit_transfer(devc, devc->acquisition->xfer_in); break; case STATE_STOP_CAPTURE: if (sdi->status == SR_ST_ACTIVE) request_capture_length(sdi); else end_acquisition(sdi); break; case STATE_LENGTH_REQUEST: devc->state = STATE_LENGTH_RESPONSE; submit_transfer(devc, devc->acquisition->xfer_in); break; case STATE_READ_PREPARE: request_read_mem(sdi); break; case STATE_READ_REQUEST: devc->state = STATE_READ_RESPONSE; submit_transfer(devc, devc->acquisition->xfer_in); break; case STATE_READ_END: end_acquisition(sdi); break; default: sr_err("Unexpected device state %d.", devc->state); break; } } } /* USB input transfer completion callback. */ static void receive_transfer_in(struct libusb_transfer *transfer) { struct sr_dev_inst *sdi; struct dev_context *devc; struct acquisition_state *acq; sdi = transfer->user_data; devc = sdi->priv; acq = devc->acquisition; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { sr_err("Transfer from device failed: %d.", transfer->status); devc->transfer_error = TRUE; return; } switch (devc->state) { case STATE_STATUS_RESPONSE: process_capture_status(sdi); break; case STATE_LENGTH_RESPONSE: process_capture_length(sdi); break; case STATE_READ_RESPONSE: if (process_sample_data(sdi) == SR_OK && acq->mem_addr_next < acq->mem_addr_stop && acq->samples_done < acq->samples_max) request_read_mem(sdi); else issue_read_end(sdi); break; default: sr_err("Unexpected device state %d.", devc->state); break; } } /* Initialize the LWLA. This downloads a bitstream into the FPGA * and executes a simple device test sequence. */ SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; uint32_t value; devc = sdi->priv; /* Force reload of bitstream */ devc->cur_clock_config = CONF_CLOCK_NONE; ret = lwla_set_clock_config(sdi); if (ret != SR_OK) return ret; ret = lwla_write_reg(sdi->conn, REG_CMD_CTRL2, 100); if (ret != SR_OK) return ret; ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL1, &value); if (ret != SR_OK) return ret; sr_dbg("Received test word 0x%08X back.", value); if (value != 0x12345678) return SR_ERR; ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL4, &value); if (ret != SR_OK) return ret; sr_dbg("Received test word 0x%08X back.", value); if (value != 0x12345678) return SR_ERR; ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL3, &value); if (ret != SR_OK) return ret; sr_dbg("Received test word 0x%08X back.", value); if (value != 0x87654321) return SR_ERR; return ret; } /* Select the LWLA clock configuration. If the clock source changed from * the previous setting, this will download a new bitstream to the FPGA. */ SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; enum clock_config choice; devc = sdi->priv; if (sdi->status == SR_ST_INACTIVE) choice = CONF_CLOCK_NONE; else if (devc->cfg_clock_source == CLOCK_INTERNAL) choice = CONF_CLOCK_INT; else if (devc->cfg_clock_edge == EDGE_POSITIVE) choice = CONF_CLOCK_EXT_RISE; else choice = CONF_CLOCK_EXT_FALL; if (choice != devc->cur_clock_config) { devc->cur_clock_config = CONF_CLOCK_NONE; ret = lwla_send_bitstream(sdi->conn, bitstream_map[choice]); if (ret == SR_OK) devc->cur_clock_config = choice; return ret; } return SR_OK; } /* Configure the LWLA in preparation for an acquisition session. */ SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; struct acquisition_state *acq; struct regval_pair regvals[7]; int ret; devc = sdi->priv; usb = sdi->conn; acq = devc->acquisition; if (devc->limit_msec > 0) { acq->duration_max = devc->limit_msec; sr_info("Acquisition time limit %" PRIu64 " ms.", devc->limit_msec); } else acq->duration_max = MAX_LIMIT_MSEC; if (devc->limit_samples > 0) { acq->samples_max = devc->limit_samples; sr_info("Acquisition sample count limit %" PRIu64 ".", devc->limit_samples); } else acq->samples_max = MAX_LIMIT_SAMPLES; if (devc->cfg_clock_source == CLOCK_INTERNAL) { sr_info("Internal clock, samplerate %" PRIu64 ".", devc->samplerate); if (devc->samplerate == 0) return SR_ERR_BUG; /* At 125 MHz, the clock divider is bypassed. */ acq->bypass_clockdiv = (devc->samplerate > SR_MHZ(100)); /* If only one of the limits is set, derive the other one. */ if (devc->limit_msec == 0 && devc->limit_samples > 0) acq->duration_max = devc->limit_samples * 1000 / devc->samplerate + 1; else if (devc->limit_samples == 0 && devc->limit_msec > 0) acq->samples_max = devc->limit_msec * devc->samplerate / 1000; } else { acq->bypass_clockdiv = TRUE; if (devc->cfg_clock_edge == EDGE_NEGATIVE) sr_info("External clock, falling edge."); else sr_info("External clock, rising edge."); } regvals[0].reg = REG_MEM_CTRL2; regvals[0].val = 2; regvals[1].reg = REG_MEM_CTRL2; regvals[1].val = 1; regvals[2].reg = REG_CMD_CTRL2; regvals[2].val = 10; regvals[3].reg = REG_CMD_CTRL3; regvals[3].val = 0x74; regvals[4].reg = REG_CMD_CTRL4; regvals[4].val = 0; regvals[5].reg = REG_CMD_CTRL1; regvals[5].val = 0; regvals[6].reg = REG_DIV_BYPASS; regvals[6].val = acq->bypass_clockdiv; ret = lwla_write_regs(usb, regvals, G_N_ELEMENTS(regvals)); if (ret != SR_OK) return ret; return capture_setup(sdi); } /* Start the capture operation on the LWLA device. Beginning with this * function, all USB transfers will be asynchronous until the end of the * acquisition session. */ SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; struct acquisition_state *acq; struct regval_pair *regvals; devc = sdi->priv; usb = sdi->conn; acq = devc->acquisition; acq->duration_now = 0; acq->mem_addr_fill = 0; acq->capture_flags = 0; libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND, (unsigned char *)acq->xfer_buf_out, 0, &receive_transfer_out, (struct sr_dev_inst *)sdi, USB_TIMEOUT); libusb_fill_bulk_transfer(acq->xfer_in, usb->devhdl, EP_REPLY, (unsigned char *)acq->xfer_buf_in, sizeof acq->xfer_buf_in, &receive_transfer_in, (struct sr_dev_inst *)sdi, USB_TIMEOUT); regvals = devc->reg_write_seq; regvals[0].reg = REG_CMD_CTRL2; regvals[0].val = 10; regvals[1].reg = REG_CMD_CTRL3; regvals[1].val = 1; regvals[2].reg = REG_CMD_CTRL4; regvals[2].val = 0; regvals[3].reg = REG_CMD_CTRL1; regvals[3].val = 0; devc->reg_write_pos = 0; devc->reg_write_len = 4; devc->state = STATE_START_CAPTURE; return issue_next_write_reg(sdi); } /* Allocate an acquisition state object. */ SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void) { struct acquisition_state *acq; acq = g_try_new0(struct acquisition_state, 1); if (!acq) { sr_err("Acquisition state malloc failed."); return NULL; } acq->xfer_in = libusb_alloc_transfer(0); if (!acq->xfer_in) { sr_err("Transfer malloc failed."); g_free(acq); return NULL; } acq->xfer_out = libusb_alloc_transfer(0); if (!acq->xfer_out) { sr_err("Transfer malloc failed."); libusb_free_transfer(acq->xfer_in); g_free(acq); return NULL; } return acq; } /* Deallocate an acquisition state object. */ SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq) { if (acq) { libusb_free_transfer(acq->xfer_out); libusb_free_transfer(acq->xfer_in); g_free(acq); } } /* USB I/O source callback. */ SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; struct drv_context *drvc; struct timeval tv; int ret; (void)fd; sdi = cb_data; devc = sdi->priv; drvc = sdi->driver->priv; if (!devc || !drvc) return FALSE; /* No timeout: return immediately. */ tv.tv_sec = 0; tv.tv_usec = 0; ret = libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, NULL); if (ret != 0) sr_err("Event handling failed: %s.", libusb_error_name(ret)); /* If no event flags are set the timeout must have expired. */ if (revents == 0 && devc->state == STATE_STATUS_WAIT) { if (sdi->status == SR_ST_STOPPING) issue_stop_capture(sdi); else request_capture_status(sdi); } /* Check if an error occurred on a transfer. */ if (devc->transfer_error) end_acquisition(sdi); return TRUE; } libsigrok-0.3.0/hardware/sysclk-lwla/api.c0000644000175000017500000003413412332246667015417 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2014 Daniel Elstner * * 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 . */ #include "protocol.h" #include "libsigrok.h" #include "libsigrok-internal.h" #include #include #include #include static const int32_t hwopts[] = { SR_CONF_CONN, }; static const int32_t hwcaps[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_SAMPLERATE, SR_CONF_EXTERNAL_CLOCK, SR_CONF_CLOCK_EDGE, SR_CONF_TRIGGER_TYPE, SR_CONF_TRIGGER_SOURCE, SR_CONF_TRIGGER_SLOPE, SR_CONF_LIMIT_MSEC, SR_CONF_LIMIT_SAMPLES, }; /* The hardware supports more samplerates than these, but these are the * options hardcoded into the vendor's Windows GUI. */ static const uint64_t samplerates[] = { SR_MHZ(125), SR_MHZ(100), SR_MHZ(50), SR_MHZ(20), SR_MHZ(10), SR_MHZ(5), SR_MHZ(2), SR_MHZ(1), SR_KHZ(500), SR_KHZ(200), SR_KHZ(100), SR_KHZ(50), SR_KHZ(20), SR_KHZ(10), SR_KHZ(5), SR_KHZ(2), SR_KHZ(1), SR_HZ(500), SR_HZ(200), SR_HZ(100), }; /* Names assigned to available trigger sources. Indices must match * trigger_source enum values. */ static const char *const trigger_source_names[] = { "CH", "TRG" }; /* Names assigned to available trigger slope choices. Indices must * match the signal_edge enum values. */ static const char *const signal_edge_names[] = { "r", "f" }; SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info; static struct sr_dev_driver *const di = &sysclk_lwla_driver_info; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *gen_channel_list(int num_channels) { GSList *list; struct sr_channel *ch; int i; char name[8]; list = NULL; for (i = num_channels; i > 0; --i) { /* The LWLA series simply number channels from CH1 to CHxx. */ g_snprintf(name, sizeof(name), "CH%d", i); ch = sr_channel_new(i - 1, SR_CHANNEL_LOGIC, TRUE, name); list = g_slist_prepend(list, ch); } return list; } static struct sr_dev_inst *dev_inst_new(int device_index) { struct sr_dev_inst *sdi; struct dev_context *devc; /* Allocate memory for our private driver context. */ devc = g_try_new0(struct dev_context, 1); if (!devc) { sr_err("Device context malloc failed."); return NULL; } /* Register the device with libsigrok. */ sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE, VENDOR_NAME, MODEL_NAME, NULL); if (!sdi) { sr_err("Failed to instantiate device."); g_free(devc); return NULL; } /* Enable all channels to match the default channel configuration. */ devc->channel_mask = ALL_CHANNELS_MASK; devc->samplerate = DEFAULT_SAMPLERATE; sdi->priv = devc; sdi->channels = gen_channel_list(NUM_CHANNELS); return sdi; } static GSList *scan(GSList *options) { GSList *usb_devices, *devices, *node; struct drv_context *drvc; struct sr_dev_inst *sdi; struct sr_usb_dev_inst *usb; struct sr_config *src; const char *conn; int device_index; drvc = di->priv; conn = USB_VID_PID; for (node = options; node != NULL; node = node->next) { src = node->data; if (src->key == SR_CONF_CONN) { conn = g_variant_get_string(src->data, NULL); break; } } usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); devices = NULL; device_index = g_slist_length(drvc->instances); for (node = usb_devices; node != NULL; node = node->next) { usb = node->data; /* Create sigrok device instance. */ sdi = dev_inst_new(device_index); if (!sdi) { sr_usb_dev_inst_free(usb); continue; } sdi->driver = di; sdi->inst_type = SR_INST_USB; sdi->conn = usb; /* Register device instance with driver. */ drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); } g_slist_free(usb_devices); return devices; } static GSList *dev_list(void) { struct drv_context *drvc; drvc = di->priv; return drvc->instances; } static void clear_dev_context(void *priv) { struct dev_context *devc; devc = priv; sr_dbg("Device context cleared."); lwla_free_acquisition_state(devc->acquisition); g_free(devc); } static int dev_clear(void) { return std_dev_clear(di, &clear_dev_context); } static int dev_open(struct sr_dev_inst *sdi) { struct drv_context *drvc; struct sr_usb_dev_inst *usb; int ret; drvc = di->priv; if (!drvc) { sr_err("Driver was not initialized."); return SR_ERR; } usb = sdi->conn; ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb); if (ret != SR_OK) return ret; ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); if (ret < 0) { sr_err("Failed to claim interface: %s.", libusb_error_name(ret)); return SR_ERR; } sdi->status = SR_ST_INITIALIZING; ret = lwla_init_device(sdi); if (ret == SR_OK) sdi->status = SR_ST_ACTIVE; return ret; } static int dev_close(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; if (!di->priv) { sr_err("Driver was not initialized."); return SR_ERR; } usb = sdi->conn; if (!usb->devhdl) return SR_OK; sdi->status = SR_ST_INACTIVE; /* Trigger download of the shutdown bitstream. */ if (lwla_set_clock_config(sdi) != SR_OK) sr_err("Unable to shut down device."); libusb_release_interface(usb->devhdl, USB_INTERFACE); libusb_close(usb->devhdl); usb->devhdl = NULL; return SR_OK; } static int cleanup(void) { return dev_clear(); } static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; size_t idx; (void)cg; if (!sdi) return SR_ERR_ARG; devc = sdi->priv; switch (key) { case SR_CONF_SAMPLERATE: *data = g_variant_new_uint64(devc->samplerate); break; case SR_CONF_LIMIT_MSEC: *data = g_variant_new_uint64(devc->limit_msec); break; case SR_CONF_LIMIT_SAMPLES: *data = g_variant_new_uint64(devc->limit_samples); break; case SR_CONF_EXTERNAL_CLOCK: *data = g_variant_new_boolean(devc->cfg_clock_source == CLOCK_EXT_CLK); break; case SR_CONF_CLOCK_EDGE: idx = devc->cfg_clock_edge; if (idx >= G_N_ELEMENTS(signal_edge_names)) return SR_ERR_BUG; *data = g_variant_new_string(signal_edge_names[idx]); break; case SR_CONF_TRIGGER_SOURCE: idx = devc->cfg_trigger_source; if (idx >= G_N_ELEMENTS(trigger_source_names)) return SR_ERR_BUG; *data = g_variant_new_string(trigger_source_names[idx]); break; case SR_CONF_TRIGGER_SLOPE: idx = devc->cfg_trigger_slope; if (idx >= G_N_ELEMENTS(signal_edge_names)) return SR_ERR_BUG; *data = g_variant_new_string(signal_edge_names[idx]); break; default: return SR_ERR_NA; } return SR_OK; } /* Helper for mapping a string-typed configuration value to an index * within a table of possible values. */ static int lookup_index(GVariant *value, const char *const *table, int len) { const char *entry; int i; entry = g_variant_get_string(value, NULL); if (!entry) return -1; /* Linear search is fine for very small tables. */ for (i = 0; i < len; ++i) { if (strcmp(entry, table[i]) == 0) return i; } return -1; } static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { uint64_t value; struct dev_context *devc; int idx; (void)cg; devc = sdi->priv; if (!devc) return SR_ERR_DEV_CLOSED; switch (key) { case SR_CONF_SAMPLERATE: value = g_variant_get_uint64(data); if (value < samplerates[G_N_ELEMENTS(samplerates) - 1] || value > samplerates[0]) return SR_ERR_SAMPLERATE; devc->samplerate = value; break; case SR_CONF_LIMIT_MSEC: value = g_variant_get_uint64(data); if (value > MAX_LIMIT_MSEC) return SR_ERR_ARG; devc->limit_msec = value; break; case SR_CONF_LIMIT_SAMPLES: value = g_variant_get_uint64(data); if (value > MAX_LIMIT_SAMPLES) return SR_ERR_ARG; devc->limit_samples = value; break; case SR_CONF_EXTERNAL_CLOCK: devc->cfg_clock_source = (g_variant_get_boolean(data)) ? CLOCK_EXT_CLK : CLOCK_INTERNAL; break; case SR_CONF_CLOCK_EDGE: idx = lookup_index(data, signal_edge_names, G_N_ELEMENTS(signal_edge_names)); if (idx < 0) return SR_ERR_ARG; devc->cfg_clock_edge = idx; break; case SR_CONF_TRIGGER_SOURCE: idx = lookup_index(data, trigger_source_names, G_N_ELEMENTS(trigger_source_names)); if (idx < 0) return SR_ERR_ARG; devc->cfg_trigger_source = idx; break; case SR_CONF_TRIGGER_SLOPE: idx = lookup_index(data, signal_edge_names, G_N_ELEMENTS(signal_edge_names)); if (idx < 0) return SR_ERR_ARG; devc->cfg_trigger_slope = idx; break; default: return SR_ERR_NA; } return SR_OK; } static int config_channel_set(const struct sr_dev_inst *sdi, struct sr_channel *ch, unsigned int changes) { uint64_t channel_bit; uint64_t trigger_mask; uint64_t trigger_values; uint64_t trigger_edge_mask; struct dev_context *devc; devc = sdi->priv; if (!devc) return SR_ERR_DEV_CLOSED; if (ch->index < 0 || ch->index >= NUM_CHANNELS) { sr_err("Channel index %d out of range.", ch->index); return SR_ERR_BUG; } channel_bit = (uint64_t)1 << ch->index; if ((changes & SR_CHANNEL_SET_ENABLED) != 0) { /* Enable or disable input channel for this channel. */ if (ch->enabled) devc->channel_mask |= channel_bit; else devc->channel_mask &= ~channel_bit; } if ((changes & SR_CHANNEL_SET_TRIGGER) != 0) { trigger_mask = devc->trigger_mask & ~channel_bit; trigger_values = devc->trigger_values & ~channel_bit; trigger_edge_mask = devc->trigger_edge_mask & ~channel_bit; if (ch->trigger && ch->trigger[0] != '\0') { if (ch->trigger[1] != '\0') { sr_warn("Trigger configuration \"%s\" with " "multiple stages is not supported.", ch->trigger); return SR_ERR_ARG; } /* Enable trigger for this channel. */ trigger_mask |= channel_bit; /* Configure edge mask and trigger value. */ switch (ch->trigger[0]) { case '1': trigger_values |= channel_bit; case '0': break; case 'r': trigger_values |= channel_bit; case 'f': trigger_edge_mask |= channel_bit; break; default: sr_warn("Trigger type '%c' is not supported.", ch->trigger[0]); return SR_ERR_ARG; } } /* Store validated trigger setup. */ devc->trigger_mask = trigger_mask; devc->trigger_values = trigger_values; devc->trigger_edge_mask = trigger_edge_mask; } return SR_OK; } static int config_commit(const struct sr_dev_inst *sdi) { if (sdi->status != SR_ST_ACTIVE) { sr_err("Device not ready (status %d).", (int)sdi->status); return SR_ERR; } return lwla_set_clock_config(sdi); } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { GVariant *gvar; GVariantBuilder gvb; (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, G_N_ELEMENTS(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, G_N_ELEMENTS(hwcaps), sizeof(int32_t)); break; 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, G_N_ELEMENTS(samplerates), sizeof(uint64_t)); g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; case SR_CONF_TRIGGER_TYPE: *data = g_variant_new_string(TRIGGER_TYPES); break; case SR_CONF_TRIGGER_SOURCE: *data = g_variant_new_strv(trigger_source_names, G_N_ELEMENTS(trigger_source_names)); break; case SR_CONF_TRIGGER_SLOPE: case SR_CONF_CLOCK_EDGE: *data = g_variant_new_strv(signal_edge_names, G_N_ELEMENTS(signal_edge_names)); break; default: return SR_ERR_NA; } return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct drv_context *drvc; struct dev_context *devc; struct acquisition_state *acq; int ret; (void)cb_data; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; drvc = di->priv; if (devc->acquisition) { sr_err("Acquisition still in progress?"); return SR_ERR; } acq = lwla_alloc_acquisition_state(); if (!acq) return SR_ERR_MALLOC; devc->stopping_in_progress = FALSE; devc->transfer_error = FALSE; sr_info("Starting acquisition."); devc->acquisition = acq; ret = lwla_setup_acquisition(sdi); if (ret != SR_OK) { sr_err("Failed to set up acquisition."); devc->acquisition = NULL; lwla_free_acquisition_state(acq); return ret; } ret = lwla_start_acquisition(sdi); if (ret != SR_OK) { sr_err("Failed to start acquisition."); devc->acquisition = NULL; lwla_free_acquisition_state(acq); return ret; } usb_source_add(drvc->sr_ctx, 100, &lwla_receive_data, (struct sr_dev_inst *)sdi); sr_info("Waiting for data."); /* Send header packet to the session bus. */ std_session_send_df_header(sdi, LOG_PREFIX); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; sr_dbg("Stopping acquisition."); sdi->status = SR_ST_STOPPING; return SR_OK; } SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info = { .name = "sysclk-lwla", .longname = "SysClk LWLA series", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = dev_clear, .config_get = config_get, .config_set = config_set, .config_channel_set = config_channel_set, .config_commit = config_commit, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/saleae-logic16/0000755000175000017500000000000012332246734014777 500000000000000libsigrok-0.3.0/hardware/saleae-logic16/protocol.h0000644000175000017500000000541312332246667016741 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Marcus Comstedt * Copyright (C) 2013 Bert Vermeulen * Copyright (C) 2012 Joel Holdsworth * * 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 . */ #ifndef LIBSIGROK_HARDWARE_SALEAE_LOGIC16_PROTOCOL_H #define LIBSIGROK_HARDWARE_SALEAE_LOGIC16_PROTOCOL_H #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "saleae-logic16" enum voltage_range { VOLTAGE_RANGE_UNKNOWN, VOLTAGE_RANGE_18_33_V, /* 1.8V and 3.3V logic */ VOLTAGE_RANGE_5_V, /* 5V logic */ }; /** Private, per-device-instance driver context. */ struct dev_context { /* * Since we can't keep track of a Logic16 device after upgrading * the firmware (it renumerates into a different device address * after the upgrade) this is like a global lock. No device will open * until a proper delay after the last device was upgraded. */ int64_t fw_updated; /** The currently configured samplerate of the device. */ uint64_t cur_samplerate; /** Maximum number of samples to capture, if nonzero. */ uint64_t limit_samples; /** The currently configured input voltage of the device. */ enum voltage_range cur_voltage_range; /** The input voltage selected by the user. */ enum voltage_range selected_voltage_range; /** Channels to use. */ uint16_t cur_channels; /* EEPROM data from address 8. */ uint8_t eeprom_data[8]; int64_t num_samples; int submitted_transfers; int empty_transfer_count; int num_channels, cur_channel, unitsize; uint16_t channel_masks[16]; uint16_t channel_data[16]; uint8_t *convbuffer; size_t convbuffer_size; void *cb_data; unsigned int num_transfers; struct libusb_transfer **transfers; struct sr_context *ctx; }; SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi, uint64_t samplerate, uint16_t channels); SR_PRIV int logic16_start_acquisition(const struct sr_dev_inst *sdi); SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi); SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi); SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer); #endif libsigrok-0.3.0/hardware/saleae-logic16/protocol.c0000644000175000017500000004553112332246667016741 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Marcus Comstedt * Copyright (C) 2013 Bert Vermeulen * Copyright (C) 2012 Joel Holdsworth * * 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 . */ #include "protocol.h" #include #include #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define FPGA_FIRMWARE_18 FIRMWARE_DIR"/saleae-logic16-fpga-18.bitstream" #define FPGA_FIRMWARE_33 FIRMWARE_DIR"/saleae-logic16-fpga-33.bitstream" #define MAX_SAMPLE_RATE SR_MHZ(100) #define MAX_4CH_SAMPLE_RATE SR_MHZ(50) #define MAX_7CH_SAMPLE_RATE SR_MHZ(40) #define MAX_8CH_SAMPLE_RATE SR_MHZ(32) #define MAX_10CH_SAMPLE_RATE SR_MHZ(25) #define MAX_13CH_SAMPLE_RATE SR_MHZ(16) #define BASE_CLOCK_0_FREQ SR_MHZ(100) #define BASE_CLOCK_1_FREQ SR_MHZ(160) #define COMMAND_START_ACQUISITION 1 #define COMMAND_ABORT_ACQUISITION_ASYNC 2 #define COMMAND_WRITE_EEPROM 6 #define COMMAND_READ_EEPROM 7 #define COMMAND_WRITE_LED_TABLE 0x7a #define COMMAND_SET_LED_MODE 0x7b #define COMMAND_RETURN_TO_BOOTLOADER 0x7c #define COMMAND_ABORT_ACQUISITION_SYNC 0x7d #define COMMAND_FPGA_UPLOAD_INIT 0x7e #define COMMAND_FPGA_UPLOAD_SEND_DATA 0x7f #define COMMAND_FPGA_WRITE_REGISTER 0x80 #define COMMAND_FPGA_READ_REGISTER 0x81 #define COMMAND_GET_REVID 0x82 #define WRITE_EEPROM_COOKIE1 0x42 #define WRITE_EEPROM_COOKIE2 0x55 #define READ_EEPROM_COOKIE1 0x33 #define READ_EEPROM_COOKIE2 0x81 #define ABORT_ACQUISITION_SYNC_PATTERN 0x55 #define MAX_EMPTY_TRANSFERS 64 static void encrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt) { uint8_t state1 = 0x9b, state2 = 0x54; uint8_t t, v; int i; for (i = 0; i < cnt; i++) { v = src[i]; t = (((v ^ state2 ^ 0x2b) - 0x05) ^ 0x35) - 0x39; t = (((t ^ state1 ^ 0x5a) - 0xb0) ^ 0x38) - 0x45; dest[i] = state2 = t; state1 = v; } } static void decrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt) { uint8_t state1 = 0x9b, state2 = 0x54; uint8_t t, v; int i; for (i = 0; i < cnt; i++) { v = src[i]; t = (((v + 0x45) ^ 0x38) + 0xb0) ^ 0x5a ^ state1; t = (((t + 0x39) ^ 0x35) + 0x05) ^ 0x2b ^ state2; dest[i] = state1 = t; state2 = v; } } static int do_ep1_command(const struct sr_dev_inst *sdi, const uint8_t *command, uint8_t cmd_len, uint8_t *reply, uint8_t reply_len) { uint8_t buf[64]; struct sr_usb_dev_inst *usb; int ret, xfer; usb = sdi->conn; if (cmd_len < 1 || cmd_len > 64 || reply_len > 64 || command == NULL || (reply_len > 0 && reply == NULL)) return SR_ERR_ARG; encrypt(buf, command, cmd_len); ret = libusb_bulk_transfer(usb->devhdl, 1, buf, cmd_len, &xfer, 1000); if (ret != 0) { sr_dbg("Failed to send EP1 command 0x%02x: %s.", command[0], libusb_error_name(ret)); return SR_ERR; } if (xfer != cmd_len) { sr_dbg("Failed to send EP1 command 0x%02x: incorrect length " "%d != %d.", xfer, cmd_len); return SR_ERR; } if (reply_len == 0) return SR_OK; ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, buf, reply_len, &xfer, 1000); if (ret != 0) { sr_dbg("Failed to receive reply to EP1 command 0x%02x: %s.", command[0], libusb_error_name(ret)); return SR_ERR; } if (xfer != reply_len) { sr_dbg("Failed to receive reply to EP1 command 0x%02x: " "incorrect length %d != %d.", xfer, reply_len); return SR_ERR; } decrypt(reply, buf, reply_len); return SR_OK; } static int read_eeprom(const struct sr_dev_inst *sdi, uint8_t address, uint8_t length, uint8_t *buf) { uint8_t command[5] = { COMMAND_READ_EEPROM, READ_EEPROM_COOKIE1, READ_EEPROM_COOKIE2, address, length, }; return do_ep1_command(sdi, command, 5, buf, length); } static int upload_led_table(const struct sr_dev_inst *sdi, const uint8_t *table, uint8_t offset, uint8_t cnt) { uint8_t chunk, command[64]; int ret; if (cnt < 1 || cnt + offset > 64 || table == NULL) return SR_ERR_ARG; while (cnt > 0) { chunk = (cnt > 32 ? 32 : cnt); command[0] = COMMAND_WRITE_LED_TABLE; command[1] = offset; command[2] = chunk; memcpy(command + 3, table, chunk); ret = do_ep1_command(sdi, command, 3 + chunk, NULL, 0); if (ret != SR_OK) return ret; table += chunk; offset += chunk; cnt -= chunk; } return SR_OK; } static int set_led_mode(const struct sr_dev_inst *sdi, uint8_t animate, uint16_t t2reload, uint8_t div, uint8_t repeat) { uint8_t command[6] = { COMMAND_SET_LED_MODE, animate, t2reload & 0xff, t2reload >> 8, div, repeat, }; return do_ep1_command(sdi, command, 6, NULL, 0); } static int read_fpga_register(const struct sr_dev_inst *sdi, uint8_t address, uint8_t *value) { uint8_t command[3] = { COMMAND_FPGA_READ_REGISTER, 1, address, }; return do_ep1_command(sdi, command, 3, value, 1); } static int write_fpga_registers(const struct sr_dev_inst *sdi, uint8_t (*regs)[2], uint8_t cnt) { uint8_t command[64]; int i; if (cnt < 1 || cnt > 31) return SR_ERR_ARG; command[0] = COMMAND_FPGA_WRITE_REGISTER; command[1] = cnt; for (i = 0; i < cnt; i++) { command[2 + 2 * i] = regs[i][0]; command[3 + 2 * i] = regs[i][1]; } return do_ep1_command(sdi, command, 2 * (cnt + 1), NULL, 0); } static int write_fpga_register(const struct sr_dev_inst *sdi, uint8_t address, uint8_t value) { uint8_t regs[2] = { address, value }; return write_fpga_registers(sdi, ®s, 1); } static uint8_t map_eeprom_data(uint8_t v) { return (((v ^ 0x80) + 0x44) ^ 0xd5) + 0x69; } static int prime_fpga(const struct sr_dev_inst *sdi) { uint8_t eeprom_data[16]; uint8_t old_reg_10, version; uint8_t regs[8][2] = { {10, 0x00}, {10, 0x40}, {12, 0}, {10, 0xc0}, {10, 0x40}, {6, 0}, {7, 1}, {7, 0} }; int i, ret; if ((ret = read_eeprom(sdi, 16, 16, eeprom_data)) != SR_OK) return ret; if ((ret = read_fpga_register(sdi, 10, &old_reg_10)) != SR_OK) return ret; regs[0][1] = (old_reg_10 &= 0x7f); regs[1][1] |= old_reg_10; regs[3][1] |= old_reg_10; regs[4][1] |= old_reg_10; for (i = 0; i < 16; i++) { regs[2][1] = eeprom_data[i]; regs[5][1] = map_eeprom_data(eeprom_data[i]); if (i) ret = write_fpga_registers(sdi, ®s[2], 6); else ret = write_fpga_registers(sdi, ®s[0], 8); if (ret != SR_OK) return ret; } if ((ret = write_fpga_register(sdi, 10, old_reg_10)) != SR_OK) return ret; if ((ret = read_fpga_register(sdi, 0, &version)) != SR_OK) return ret; if (version != 0x10) { sr_err("Invalid FPGA bitstream version: 0x%02x != 0x10.", version); return SR_ERR; } return SR_OK; } static void make_heartbeat(uint8_t *table, int len) { int i, j; memset(table, 0, len); len >>= 3; for (i = 0; i < 2; i++) for (j = 0; j < len; j++) *table++ = sin(j * M_PI / len) * 255; } static int configure_led(const struct sr_dev_inst *sdi) { uint8_t table[64]; int ret; make_heartbeat(table, 64); if ((ret = upload_led_table(sdi, table, 0, 64)) != SR_OK) return ret; return set_led_mode(sdi, 1, 6250, 0, 1); } static int upload_fpga_bitstream(const struct sr_dev_inst *sdi, enum voltage_range vrange) { struct dev_context *devc; int offset, chunksize, ret; const char *filename; uint8_t len, buf[256 * 62], command[64]; FILE *fw; devc = sdi->priv; if (devc->cur_voltage_range == vrange) return SR_OK; switch (vrange) { case VOLTAGE_RANGE_18_33_V: filename = FPGA_FIRMWARE_18; break; case VOLTAGE_RANGE_5_V: filename = FPGA_FIRMWARE_33; break; default: sr_err("Unsupported voltage range."); return SR_ERR; } sr_info("Uploading FPGA bitstream at %s.", filename); if ((fw = g_fopen(filename, "rb")) == NULL) { sr_err("Unable to open bitstream file %s for reading: %s.", filename, strerror(errno)); return SR_ERR; } buf[0] = COMMAND_FPGA_UPLOAD_INIT; if ((ret = do_ep1_command(sdi, buf, 1, NULL, 0)) != SR_OK) { fclose(fw); return ret; } while (1) { chunksize = fread(buf, 1, sizeof(buf), fw); if (chunksize == 0) break; for (offset = 0; offset < chunksize; offset += 62) { len = (offset + 62 > chunksize ? chunksize - offset : 62); command[0] = COMMAND_FPGA_UPLOAD_SEND_DATA; command[1] = len; memcpy(command + 2, buf + offset, len); ret = do_ep1_command(sdi, command, len + 2, NULL, 0); if (ret != SR_OK) { fclose(fw); return ret; } } sr_info("Uploaded %d bytes.", chunksize); } fclose(fw); sr_info("FPGA bitstream upload done."); if ((ret = prime_fpga(sdi)) != SR_OK) return ret; if ((ret = configure_led(sdi)) != SR_OK) return ret; devc->cur_voltage_range = vrange; return SR_OK; } static int abort_acquisition_sync(const struct sr_dev_inst *sdi) { static const uint8_t command[2] = { COMMAND_ABORT_ACQUISITION_SYNC, ABORT_ACQUISITION_SYNC_PATTERN, }; uint8_t reply, expected_reply; int ret; if ((ret = do_ep1_command(sdi, command, 2, &reply, 1)) != SR_OK) return ret; expected_reply = ~command[1]; if (reply != expected_reply) { sr_err("Invalid response for abort acquisition command: " "0x%02x != 0x%02x.", reply, expected_reply); return SR_ERR; } return SR_OK; } SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi, uint64_t samplerate, uint16_t channels) { uint8_t clock_select, reg1, reg10; uint64_t div; int i, ret, nchan = 0; struct dev_context *devc; devc = sdi->priv; if (samplerate == 0 || samplerate > MAX_SAMPLE_RATE) { sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate); return SR_ERR; } if (BASE_CLOCK_0_FREQ % samplerate == 0 && (div = BASE_CLOCK_0_FREQ / samplerate) <= 256) { clock_select = 0; } else if (BASE_CLOCK_1_FREQ % samplerate == 0 && (div = BASE_CLOCK_1_FREQ / samplerate) <= 256) { clock_select = 1; } else { sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate); return SR_ERR; } for (i = 0; i < 16; i++) if (channels & (1U << i)) nchan++; if ((nchan >= 13 && samplerate > MAX_13CH_SAMPLE_RATE) || (nchan >= 10 && samplerate > MAX_10CH_SAMPLE_RATE) || (nchan >= 8 && samplerate > MAX_8CH_SAMPLE_RATE) || (nchan >= 7 && samplerate > MAX_7CH_SAMPLE_RATE) || (nchan >= 4 && samplerate > MAX_4CH_SAMPLE_RATE)) { sr_err("Unable to sample at %" PRIu64 "Hz " "with this many channels.", samplerate); return SR_ERR; } ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range); if (ret != SR_OK) return ret; if ((ret = read_fpga_register(sdi, 1, ®1)) != SR_OK) return ret; if (reg1 != 0x08) { sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x08.", reg1); return SR_ERR; } if ((ret = write_fpga_register(sdi, 1, 0x40)) != SR_OK) return ret; if ((ret = write_fpga_register(sdi, 10, clock_select)) != SR_OK) return ret; if ((ret = write_fpga_register(sdi, 4, (uint8_t)(div - 1))) != SR_OK) return ret; if ((ret = write_fpga_register(sdi, 2, (uint8_t)(channels & 0xff))) != SR_OK) return ret; if ((ret = write_fpga_register(sdi, 3, (uint8_t)(channels >> 8))) != SR_OK) return ret; if ((ret = write_fpga_register(sdi, 1, 0x42)) != SR_OK) return ret; if ((ret = write_fpga_register(sdi, 1, 0x40)) != SR_OK) return ret; if ((ret = read_fpga_register(sdi, 1, ®1)) != SR_OK) return ret; if (reg1 != 0x48) { sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x48.", reg1); return SR_ERR; } if ((ret = read_fpga_register(sdi, 10, ®10)) != SR_OK) return ret; if (reg10 != clock_select) { sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x%02x.", reg10, clock_select); return SR_ERR; } return SR_OK; } SR_PRIV int logic16_start_acquisition(const struct sr_dev_inst *sdi) { static const uint8_t command[1] = { COMMAND_START_ACQUISITION, }; int ret; if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK) return ret; return write_fpga_register(sdi, 1, 0x41); } SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi) { static const uint8_t command[1] = { COMMAND_ABORT_ACQUISITION_ASYNC, }; int ret; uint8_t reg1, reg8, reg9; if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK) return ret; if ((ret = write_fpga_register(sdi, 1, 0x00)) != SR_OK) return ret; if ((ret = read_fpga_register(sdi, 1, ®1)) != SR_OK) return ret; if (reg1 != 0x08) { sr_dbg("Invalid state at acquisition stop: 0x%02x != 0x08.", reg1); return SR_ERR; } if ((ret = read_fpga_register(sdi, 8, ®8)) != SR_OK) return ret; if ((ret = read_fpga_register(sdi, 9, ®9)) != SR_OK) return ret; return SR_OK; } SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; devc = sdi->priv; devc->cur_voltage_range = VOLTAGE_RANGE_UNKNOWN; if ((ret = abort_acquisition_sync(sdi)) != SR_OK) return ret; if ((ret = read_eeprom(sdi, 8, 8, devc->eeprom_data)) != SR_OK) return ret; ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range); if (ret != SR_OK) return ret; return SR_OK; } static void finish_acquisition(struct dev_context *devc) { struct sr_datafeed_packet packet; /* Terminate session. */ packet.type = SR_DF_END; sr_session_send(devc->cb_data, &packet); /* Remove fds from polling. */ usb_source_remove(devc->ctx); devc->num_transfers = 0; g_free(devc->transfers); g_free(devc->convbuffer); } static void free_transfer(struct libusb_transfer *transfer) { struct dev_context *devc; unsigned int i; devc = transfer->user_data; g_free(transfer->buffer); transfer->buffer = NULL; libusb_free_transfer(transfer); for (i = 0; i < devc->num_transfers; i++) { if (devc->transfers[i] == transfer) { devc->transfers[i] = NULL; break; } } devc->submitted_transfers--; if (devc->submitted_transfers == 0) finish_acquisition(devc); } static void resubmit_transfer(struct libusb_transfer *transfer) { int ret; if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS) return; free_transfer(transfer); /* TODO: Stop session? */ sr_err("%s: %s", __func__, libusb_error_name(ret)); } static size_t convert_sample_data_16(struct dev_context *devc, uint8_t *dest, size_t destcnt, const uint8_t *src, size_t srccnt) { uint16_t *channel_data; int i, cur_channel; size_t ret = 0; uint16_t sample, channel_mask; srccnt /= 2; channel_data = devc->channel_data; cur_channel = devc->cur_channel; while (srccnt--) { sample = src[0] | (src[1] << 8); src += 2; channel_mask = devc->channel_masks[cur_channel]; for (i = 15; i >= 0; --i, sample >>= 1) if (sample & 1) channel_data[i] |= channel_mask; if (++cur_channel == devc->num_channels) { cur_channel = 0; if (destcnt < 16 * 2) { sr_err("Conversion buffer too small!"); break; } memcpy(dest, channel_data, 16 * 2); memset(channel_data, 0, 16 * 2); dest += 16 * 2; ret += 16; destcnt -= 16 * 2; } } devc->cur_channel = cur_channel; return ret; } static size_t convert_sample_data_8(struct dev_context *devc, uint8_t *dest, size_t destcnt, const uint8_t *src, size_t srccnt) { uint8_t *channel_data; int i, cur_channel; size_t ret = 0; uint16_t sample; uint8_t channel_mask; srccnt /= 2; channel_data = (uint8_t *)devc->channel_data; cur_channel = devc->cur_channel; while (srccnt--) { sample = src[0] | (src[1] << 8); src += 2; channel_mask = devc->channel_masks[cur_channel]; for (i = 15; i >= 0; --i, sample >>= 1) if (sample & 1) channel_data[i] |= channel_mask; if (++cur_channel == devc->num_channels) { cur_channel = 0; if (destcnt < 16) { sr_err("Conversion buffer too small!"); break; } memcpy(dest, channel_data, 16); memset(channel_data, 0, 16); dest += 16; ret += 16; destcnt -= 16; } } devc->cur_channel = cur_channel; return ret; } static size_t convert_sample_data(struct dev_context *devc, uint8_t *dest, size_t destcnt, const uint8_t *src, size_t srccnt, int unitsize) { return (unitsize == 2 ? convert_sample_data_16(devc, dest, destcnt, src, srccnt) : convert_sample_data_8(devc, dest, destcnt, src, srccnt)); } SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer) { gboolean packet_has_error = FALSE; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; struct dev_context *devc; size_t converted_length; devc = transfer->user_data; /* * If acquisition has already ended, just free any queued up * transfer that come in. */ if (devc->num_samples < 0) { free_transfer(transfer); return; } sr_info("receive_transfer(): status %d received %d bytes.", transfer->status, transfer->actual_length); switch (transfer->status) { case LIBUSB_TRANSFER_NO_DEVICE: devc->num_samples = -2; free_transfer(transfer); return; case LIBUSB_TRANSFER_COMPLETED: case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ break; default: packet_has_error = TRUE; break; } if (transfer->actual_length & 1) { sr_err("Got an odd number of bytes from the device. " "This should not happen."); /* Bail out right away. */ packet_has_error = TRUE; devc->empty_transfer_count = MAX_EMPTY_TRANSFERS; } if (transfer->actual_length == 0 || packet_has_error) { devc->empty_transfer_count++; if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { /* * The FX2 gave up. End the acquisition, the frontend * will work out that the samplecount is short. */ devc->num_samples = -2; free_transfer(transfer); } else { resubmit_transfer(transfer); } return; } else { devc->empty_transfer_count = 0; } converted_length = convert_sample_data(devc, devc->convbuffer, devc->convbuffer_size, transfer->buffer, transfer->actual_length, devc->unitsize); if (converted_length > 0) { /* Cap sample count if needed. */ if (devc->limit_samples && (uint64_t)devc->num_samples + converted_length > devc->limit_samples) { converted_length = devc->limit_samples - devc->num_samples; } /* Send the incoming transfer to the session bus. */ packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = converted_length * devc->unitsize; logic.unitsize = devc->unitsize; logic.data = devc->convbuffer; sr_session_send(devc->cb_data, &packet); devc->num_samples += converted_length; if (devc->limit_samples && (uint64_t)devc->num_samples >= devc->limit_samples) { devc->num_samples = -2; free_transfer(transfer); return; } } resubmit_transfer(transfer); } libsigrok-0.3.0/hardware/saleae-logic16/api.c0000644000175000017500000004711212332246667015646 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Marcus Comstedt * Copyright (C) 2013 Bert Vermeulen * Copyright (C) 2012 Joel Holdsworth * * 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 . */ #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "protocol.h" #define LOGIC16_VID 0x21a9 #define LOGIC16_PID 0x1001 #define USB_INTERFACE 0 #define USB_CONFIGURATION 1 #define FX2_FIRMWARE FIRMWARE_DIR "/saleae-logic16-fx2.fw" #define MAX_RENUM_DELAY_MS 3000 #define NUM_SIMUL_TRANSFERS 32 SR_PRIV struct sr_dev_driver saleae_logic16_driver_info; static struct sr_dev_driver *di = &saleae_logic16_driver_info; static const int32_t hwopts[] = { SR_CONF_CONN, }; static const int32_t hwcaps[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_SAMPLERATE, SR_CONF_VOLTAGE_THRESHOLD, /* These are really implemented in the driver, not the hardware. */ SR_CONF_LIMIT_SAMPLES, SR_CONF_CONTINUOUS, }; static const char *channel_names[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", NULL, }; static const struct { enum voltage_range range; gdouble low; gdouble high; } volt_thresholds[] = { { VOLTAGE_RANGE_18_33_V, 0.7, 1.4 }, { VOLTAGE_RANGE_5_V, 1.4, 3.6 }, }; static const uint64_t samplerates[] = { SR_KHZ(500), SR_MHZ(1), SR_MHZ(2), SR_MHZ(4), SR_MHZ(5), SR_MHZ(8), SR_MHZ(10), SR_KHZ(12500), SR_MHZ(16), SR_MHZ(25), SR_MHZ(32), SR_MHZ(40), SR_MHZ(80), SR_MHZ(100), }; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static gboolean check_conf_profile(libusb_device *dev) { struct libusb_device_descriptor des; struct libusb_device_handle *hdl; gboolean ret; unsigned char strdesc[64]; hdl = NULL; ret = FALSE; while (!ret) { /* Assume the FW has not been loaded, unless proven wrong. */ if (libusb_get_device_descriptor(dev, &des) != 0) break; if (libusb_open(dev, &hdl) != 0) break; if (libusb_get_string_descriptor_ascii(hdl, des.iManufacturer, strdesc, sizeof(strdesc)) < 0) break; if (strcmp((const char *)strdesc, "Saleae LLC")) break; if (libusb_get_string_descriptor_ascii(hdl, des.iProduct, strdesc, sizeof(strdesc)) < 0) break; if (strcmp((const char *)strdesc, "Logic S/16")) break; /* If we made it here, it must be a configured Logic16. */ ret = TRUE; } if (hdl) libusb_close(hdl); return ret; } static GSList *scan(GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_usb_dev_inst *usb; struct sr_channel *ch; struct sr_config *src; GSList *l, *devices, *conn_devices; struct libusb_device_descriptor des; libusb_device **devlist; int devcnt, ret, i, j; const char *conn; drvc = di->priv; conn = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; } } if (conn) conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); else conn_devices = NULL; /* Find all Logic16 devices and upload firmware to them. */ devices = NULL; libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if (conn) { usb = NULL; for (l = conn_devices; l; l = l->next) { usb = l->data; if (usb->bus == libusb_get_bus_number(devlist[i]) && usb->address == libusb_get_device_address(devlist[i])) break; } if (!l) /* This device matched none of the ones that * matched the conn specification. */ continue; } if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) { sr_warn("Failed to get device descriptor: %s.", libusb_error_name(ret)); continue; } if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID) continue; devcnt = g_slist_length(drvc->instances); sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING, "Saleae", "Logic16", NULL); if (!sdi) return NULL; sdi->driver = di; for (j = 0; channel_names[j]; j++) { if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE, channel_names[j]))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); } if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) return NULL; devc->selected_voltage_range = VOLTAGE_RANGE_18_33_V; sdi->priv = devc; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); if (check_conf_profile(devlist[i])) { /* Already has the firmware, so fix the new address. */ sr_dbg("Found a Logic16 device."); sdi->status = SR_ST_INACTIVE; sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new( libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); } else { if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, FX2_FIRMWARE) == SR_OK) /* Store when this device's FW was updated. */ devc->fw_updated = g_get_monotonic_time(); else sr_err("Firmware upload failed for " "device %d.", devcnt); sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new( libusb_get_bus_number(devlist[i]), 0xff, NULL); } } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int logic16_dev_open(struct sr_dev_inst *sdi) { libusb_device **devlist; struct sr_usb_dev_inst *usb; struct libusb_device_descriptor des; struct drv_context *drvc; int ret, skip, i, device_count; drvc = di->priv; usb = sdi->conn; if (sdi->status == SR_ST_ACTIVE) /* Device is already in use. */ return SR_ERR; skip = 0; device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); if (device_count < 0) { sr_err("Failed to get device list: %s.", libusb_error_name(device_count)); return SR_ERR; } for (i = 0; i < device_count; i++) { if ((ret = libusb_get_device_descriptor(devlist[i], &des))) { sr_err("Failed to get device descriptor: %s.", libusb_error_name(ret)); continue; } if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID) continue; if (sdi->status == SR_ST_INITIALIZING) { if (skip != sdi->index) { /* Skip devices of this type that aren't the one we want. */ skip += 1; continue; } } else if (sdi->status == SR_ST_INACTIVE) { /* * This device is fully enumerated, so we need to find * this device by vendor, product, bus and address. */ if (libusb_get_bus_number(devlist[i]) != usb->bus || libusb_get_device_address(devlist[i]) != usb->address) /* This is not the one. */ continue; } if (!(ret = libusb_open(devlist[i], &usb->devhdl))) { if (usb->address == 0xff) /* * First time we touch this device after FW * upload, so we don't know the address yet. */ usb->address = libusb_get_device_address(devlist[i]); } else { sr_err("Failed to open device: %s.", libusb_error_name(ret)); break; } ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); if (ret == LIBUSB_ERROR_BUSY) { sr_err("Unable to claim USB interface. Another " "program or driver has already claimed it."); break; } else if (ret == LIBUSB_ERROR_NO_DEVICE) { sr_err("Device has been disconnected."); break; } else if (ret != 0) { sr_err("Unable to claim interface: %s.", libusb_error_name(ret)); break; } if ((ret = logic16_init_device(sdi)) != SR_OK) { sr_err("Failed to init device."); break; } sdi->status = SR_ST_ACTIVE; sr_info("Opened device %d on %d.%d, interface %d.", sdi->index, usb->bus, usb->address, USB_INTERFACE); break; } libusb_free_device_list(devlist, 1); if (sdi->status != SR_ST_ACTIVE) { if (usb->devhdl) { libusb_release_interface(usb->devhdl, USB_INTERFACE); libusb_close(usb->devhdl); usb->devhdl = NULL; } return SR_ERR; } return SR_OK; } static int dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; int64_t timediff_us, timediff_ms; devc = sdi->priv; /* * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS * milliseconds for the FX2 to renumerate. */ ret = SR_ERR; if (devc->fw_updated > 0) { sr_info("Waiting for device to reset."); /* Takes >= 300ms for the FX2 to be gone from the USB bus. */ g_usleep(300 * 1000); timediff_ms = 0; while (timediff_ms < MAX_RENUM_DELAY_MS) { if ((ret = logic16_dev_open(sdi)) == SR_OK) break; g_usleep(100 * 1000); timediff_us = g_get_monotonic_time() - devc->fw_updated; timediff_ms = timediff_us / 1000; sr_spew("Waited %" PRIi64 "ms.", timediff_ms); } if (ret != SR_OK) { sr_err("Device failed to renumerate."); return SR_ERR; } sr_info("Device came back after %" PRIi64 "ms.", timediff_ms); } else { sr_info("Firmware upload was not needed."); ret = logic16_dev_open(sdi); } if (ret != SR_OK) { sr_err("Unable to open device."); return SR_ERR; } if (devc->cur_samplerate == 0) { /* Samplerate hasn't been set; default to the slowest one. */ devc->cur_samplerate = samplerates[0]; } return SR_OK; } static int dev_close(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; usb = sdi->conn; if (usb->devhdl == NULL) return SR_ERR; sr_info("Closing device %d on %d.%d interface %d.", sdi->index, usb->bus, usb->address, USB_INTERFACE); libusb_release_interface(usb->devhdl, USB_INTERFACE); libusb_close(usb->devhdl); usb->devhdl = NULL; sdi->status = SR_ST_INACTIVE; return SR_OK; } static int cleanup(void) { int ret; struct drv_context *drvc; if (!(drvc = di->priv)) /* Can get called on an unused driver, doesn't matter. */ return SR_OK; ret = std_dev_clear(di, NULL); g_free(drvc); di->priv = NULL; return ret; } static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; struct sr_usb_dev_inst *usb; GVariant *range[2]; char str[128]; int ret; unsigned int i; (void)cg; ret = SR_OK; switch (key) { case SR_CONF_CONN: if (!sdi || !sdi->conn) return SR_ERR_ARG; usb = sdi->conn; if (usb->address == 255) /* Device still needs to re-enumerate after firmware * upload, so we don't know its (future) address. */ return SR_ERR; snprintf(str, 128, "%d.%d", usb->bus, usb->address); *data = g_variant_new_string(str); break; case SR_CONF_SAMPLERATE: if (!sdi) return SR_ERR; devc = sdi->priv; *data = g_variant_new_uint64(devc->cur_samplerate); break; case SR_CONF_VOLTAGE_THRESHOLD: if (!sdi) return SR_ERR; devc = sdi->priv; ret = SR_ERR; for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) { if (devc->selected_voltage_range != volt_thresholds[i].range) continue; range[0] = g_variant_new_double(volt_thresholds[i].low); range[1] = g_variant_new_double(volt_thresholds[i].high); *data = g_variant_new_tuple(range, 2); ret = SR_OK; break; } break; default: return SR_ERR_NA; } return ret; } static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; gdouble low, high; int ret; unsigned int i; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; ret = SR_OK; switch (key) { case SR_CONF_SAMPLERATE: devc->cur_samplerate = g_variant_get_uint64(data); break; case SR_CONF_LIMIT_SAMPLES: devc->limit_samples = g_variant_get_uint64(data); break; case SR_CONF_VOLTAGE_THRESHOLD: g_variant_get(data, "(dd)", &low, &high); ret = SR_ERR_ARG; for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) { if (fabs(volt_thresholds[i].low - low) < 0.1 && fabs(volt_thresholds[i].high - high) < 0.1) { devc->selected_voltage_range = volt_thresholds[i].range; ret = SR_OK; break; } } break; default: ret = SR_ERR_NA; } return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { GVariant *gvar, *range[2]; GVariantBuilder gvb; int ret; unsigned int i; (void)sdi; (void)cg; ret = SR_OK; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; 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)); g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; case SR_CONF_VOLTAGE_THRESHOLD: g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) { range[0] = g_variant_new_double(volt_thresholds[i].low); range[1] = g_variant_new_double(volt_thresholds[i].high); gvar = g_variant_new_tuple(range, 2); g_variant_builder_add_value(&gvb, gvar); } *data = g_variant_builder_end(&gvb); break; default: return SR_ERR_NA; } return ret; } static void abort_acquisition(struct dev_context *devc) { int i; devc->num_samples = -1; for (i = devc->num_transfers - 1; i >= 0; i--) { if (devc->transfers[i]) libusb_cancel_transfer(devc->transfers[i]); } } static unsigned int bytes_per_ms(struct dev_context *devc) { return devc->cur_samplerate * devc->num_channels / 8000; } static size_t get_buffer_size(struct dev_context *devc) { size_t s; /* * The buffer should be large enough to hold 10ms of data and * a multiple of 512. */ s = 10 * bytes_per_ms(devc); return (s + 511) & ~511; } static unsigned int get_number_of_transfers(struct dev_context *devc) { unsigned int n; /* Total buffer size should be able to hold about 500ms of data. */ n = 500 * bytes_per_ms(devc) / get_buffer_size(devc); if (n > NUM_SIMUL_TRANSFERS) return NUM_SIMUL_TRANSFERS; return n; } static unsigned int get_timeout(struct dev_context *devc) { size_t total_size; unsigned int timeout; total_size = get_buffer_size(devc) * get_number_of_transfers(devc); timeout = total_size / bytes_per_ms(devc); return timeout + timeout / 4; /* Leave a headroom of 25% percent. */ } static int configure_channels(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_channel *ch; GSList *l; uint16_t channel_bit; #ifdef WORDS_BIGENDIAN int i; #endif devc = sdi->priv; devc->cur_channels = 0; devc->num_channels = 0; for (l = sdi->channels; l; l = l->next) { ch = (struct sr_channel *)l->data; if (ch->enabled == FALSE) continue; channel_bit = 1 << (ch->index); devc->cur_channels |= channel_bit; #ifdef WORDS_BIGENDIAN /* * Output logic data should be stored in little endian format. * To speed things up during conversion, do the switcharoo * here instead. */ channel_bit = 1 << (ch->index ^ 8); #endif devc->channel_masks[devc->num_channels++] = channel_bit; } if (devc->cur_channels & ~0xff) { devc->unitsize = 2; } else { #ifdef WORDS_BIGENDIAN for (i = 0; i < devc->num_channels; i++) devc->channel_masks[i] >>= 8; #endif devc->unitsize = 1; } return SR_OK; } static int receive_data(int fd, int revents, void *cb_data) { struct timeval tv; struct dev_context *devc; struct drv_context *drvc; const struct sr_dev_inst *sdi; (void)fd; (void)revents; sdi = cb_data; drvc = di->priv; devc = sdi->priv; tv.tv_sec = tv.tv_usec = 0; libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv); if (devc->num_samples == -2) { logic16_abort_acquisition(sdi); abort_acquisition(devc); } return TRUE; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct drv_context *drvc; struct sr_usb_dev_inst *usb; struct libusb_transfer *transfer; unsigned int i, timeout, num_transfers; int ret; unsigned char *buf; size_t size, convsize; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; drvc = di->priv; devc = sdi->priv; usb = sdi->conn; /* Configures devc->cur_channels. */ if (configure_channels(sdi) != SR_OK) { sr_err("Failed to configure channels."); return SR_ERR; } devc->cb_data = cb_data; devc->num_samples = 0; devc->empty_transfer_count = 0; devc->cur_channel = 0; memset(devc->channel_data, 0, sizeof(devc->channel_data)); timeout = get_timeout(devc); num_transfers = get_number_of_transfers(devc); size = get_buffer_size(devc); convsize = (size / devc->num_channels + 2) * 16; devc->submitted_transfers = 0; devc->convbuffer_size = convsize; if (!(devc->convbuffer = g_try_malloc(convsize))) { sr_err("Conversion buffer malloc failed."); return SR_ERR_MALLOC; } devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers); if (!devc->transfers) { sr_err("USB transfers malloc failed."); g_free(devc->convbuffer); return SR_ERR_MALLOC; } if ((ret = logic16_setup_acquisition(sdi, devc->cur_samplerate, devc->cur_channels)) != SR_OK) { g_free(devc->transfers); g_free(devc->convbuffer); return ret; } devc->num_transfers = num_transfers; for (i = 0; i < num_transfers; i++) { if (!(buf = g_try_malloc(size))) { sr_err("USB transfer buffer malloc failed."); if (devc->submitted_transfers) abort_acquisition(devc); else { g_free(devc->transfers); g_free(devc->convbuffer); } return SR_ERR_MALLOC; } transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, usb->devhdl, 2 | LIBUSB_ENDPOINT_IN, buf, size, logic16_receive_transfer, devc, timeout); if ((ret = libusb_submit_transfer(transfer)) != 0) { sr_err("Failed to submit transfer: %s.", libusb_error_name(ret)); libusb_free_transfer(transfer); g_free(buf); abort_acquisition(devc); return SR_ERR; } devc->transfers[i] = transfer; devc->submitted_transfers++; } devc->ctx = drvc->sr_ctx; usb_source_add(devc->ctx, timeout, receive_data, (void *)sdi); /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); if ((ret = logic16_start_acquisition(sdi)) != SR_OK) { abort_acquisition(devc); return ret; } return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { int ret; (void)cb_data; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; ret = logic16_abort_acquisition(sdi); abort_acquisition(sdi->priv); return ret; } SR_PRIV struct sr_dev_driver saleae_logic16_driver_info = { .name = "saleae-logic16", .longname = "Saleae Logic16", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/appa-55ii/0000755000175000017500000000000012332246734013775 500000000000000libsigrok-0.3.0/hardware/appa-55ii/protocol.h0000644000175000017500000000401112332246667015730 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Aurelien Jacobs * * 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 . */ #ifndef LIBSIGROK_HARDWARE_APPA_55II_PROTOCOL_H #define LIBSIGROK_HARDWARE_APPA_55II_PROTOCOL_H #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "appa-55ii" #define APPA_55II_NUM_CHANNELS 2 #define APPA_55II_BUF_SIZE (4 + 32 + 1) #define DEFAULT_DATA_SOURCE DATA_SOURCE_LIVE enum { DATA_SOURCE_LIVE, DATA_SOURCE_MEMORY, }; /** Private, per-device-instance driver context. */ struct dev_context { /* Acquisition settings */ uint64_t limit_samples; /**< The sampling limit (in number of samples). */ uint64_t limit_msec; /**< The time limit (in milliseconds). */ gboolean data_source; /**< Whether to read live samples or memory */ void *session_cb_data; /**< Opaque pointer passed in by the frontend. */ /* Operational state */ uint64_t num_samples; /**< The number of already received samples. */ int64_t start_time; /**< The time at which sampling started. */ /* Temporary state across callbacks */ uint8_t buf[APPA_55II_BUF_SIZE]; unsigned int buf_len; uint8_t log_buf[64]; unsigned int log_buf_len; unsigned int num_log_records; }; SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf); SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data); #endif libsigrok-0.3.0/hardware/appa-55ii/protocol.c0000644000175000017500000001663712332246667015744 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Aurelien Jacobs * * 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 . */ #include #include #include "protocol.h" typedef enum { LIVE_DATA = 0x00, LOG_METADATA = 0x11, LOG_DATA = 0x14, LOG_START = 0x18, LOG_END = 0x19, } packet_type; static gboolean appa_55ii_checksum(const uint8_t *buf) { int i, size, checksum; size = buf[3] + 4; checksum = 0; for (i = 0; i < size; i++) checksum += buf[i]; return buf[size] == (checksum & 0xFF); } SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf) { if (buf[0] == 0x55 && buf[1] == 0x55 && buf[3] <= 32 && appa_55ii_checksum(buf)) return TRUE; return FALSE; } static uint64_t appa_55ii_flags(const uint8_t *buf) { uint8_t disp_mode; uint64_t flags; disp_mode = buf[4 + 13]; flags = 0; if ((disp_mode & 0xF0) == 0x20) flags |= SR_MQFLAG_HOLD; if ((disp_mode & 0x0C) == 0x04) flags |= SR_MQFLAG_MAX; if ((disp_mode & 0x0C) == 0x08) flags |= SR_MQFLAG_MIN; if ((disp_mode & 0x0C) == 0x0C) flags |= SR_MQFLAG_AVG; return flags; } static float appa_55ii_temp(const uint8_t *buf, int ch) { const uint8_t *ptr; int16_t temp; uint8_t flags; ptr = buf + 4 + 14 + 3 * ch; temp = RL16(ptr); flags = ptr[2]; if (flags & 0x60) return INFINITY; else if (flags & 1) return (float)temp / 10; else return (float)temp; } static void appa_55ii_live_data(struct sr_dev_inst *sdi, const uint8_t *buf) { struct dev_context *devc; struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; struct sr_channel *ch; float values[APPA_55II_NUM_CHANNELS], *val_ptr; int i; devc = sdi->priv; if (devc->data_source != DATA_SOURCE_LIVE) return; val_ptr = values; memset(&analog, 0, sizeof(analog)); analog.num_samples = 1; analog.mq = SR_MQ_TEMPERATURE; analog.unit = SR_UNIT_CELSIUS; analog.mqflags = appa_55ii_flags(buf); analog.data = values; for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) { ch = g_slist_nth_data(sdi->channels, i); if (!ch->enabled) continue; analog.channels = g_slist_append(analog.channels, ch); *val_ptr++ = appa_55ii_temp(buf, i); } packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(devc->session_cb_data, &packet); g_slist_free(analog.channels); devc->num_samples++; } static void appa_55ii_log_metadata(struct sr_dev_inst *sdi, const uint8_t *buf) { struct dev_context *devc; devc = sdi->priv; devc->num_log_records = (buf[5] << 8) + buf[4]; } static void appa_55ii_log_data_parse(struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; struct sr_channel *ch; float values[APPA_55II_NUM_CHANNELS], *val_ptr; const uint8_t *buf; int16_t temp; int offset, i; devc = sdi->priv; offset = 0; while (devc->log_buf_len >= 20 && devc->num_log_records > 0) { buf = devc->log_buf + offset; val_ptr = values; /* FIXME: Timestamp should be sent in the packet. */ sr_dbg("Timestamp: %02d:%02d:%02d", buf[2], buf[3], buf[4]); memset(&analog, 0, sizeof(analog)); analog.num_samples = 1; analog.mq = SR_MQ_TEMPERATURE; analog.unit = SR_UNIT_CELSIUS; analog.data = values; for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) { temp = RL16(buf + 12 + 2 * i); ch = g_slist_nth_data(sdi->channels, i); if (!ch->enabled) continue; analog.channels = g_slist_append(analog.channels, ch); *val_ptr++ = temp == 0x7FFF ? INFINITY : (float)temp / 10; } packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(devc->session_cb_data, &packet); g_slist_free(analog.channels); devc->num_samples++; devc->log_buf_len -= 20; offset += 20; devc->num_log_records--; } memmove(devc->log_buf, devc->log_buf + offset, devc->log_buf_len); } static void appa_55ii_log_data(struct sr_dev_inst *sdi, const uint8_t *buf) { struct dev_context *devc; const uint8_t *ptr; unsigned int size; int s; devc = sdi->priv; if (devc->data_source != DATA_SOURCE_MEMORY) return; ptr = buf + 4; size = buf[3]; while (size > 0) { s = MIN(size, sizeof(devc->log_buf) - devc->log_buf_len); memcpy(devc->log_buf + devc->log_buf_len, ptr, s); devc->log_buf_len += s; size -= s; ptr += s; appa_55ii_log_data_parse(sdi); } } static void appa_55ii_log_end(struct sr_dev_inst *sdi) { struct dev_context *devc; devc = sdi->priv; if (devc->data_source != DATA_SOURCE_MEMORY) return; sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data); } static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi, const uint8_t *buf, int len) { if (len < 5) /* Need more data. */ return NULL; if (buf[0] != 0x55 || buf[1] != 0x55) /* Try to re-synchronize on a packet start. */ return buf + 1; if (len < 5 + buf[3]) /* Need more data. */ return NULL; if (!appa_55ii_checksum(buf)) /* Skip broken packet. */ return buf + 4 + buf[3] + 1; switch ((packet_type)buf[2]) { case LIVE_DATA: appa_55ii_live_data(sdi, buf); break; case LOG_METADATA: appa_55ii_log_metadata(sdi, buf); break; case LOG_DATA: appa_55ii_log_data(sdi, buf); break; case LOG_START: break; case LOG_END: appa_55ii_log_end(sdi); break; default: sr_warn("Invalid packet type: 0x%02x.", buf[2]); break; } return buf + 4 + buf[3] + 1; } SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_serial_dev_inst *serial; int64_t time; const uint8_t *ptr, *next_ptr, *end_ptr; int len; (void)fd; if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN) return TRUE; serial = sdi->conn; /* Try to get as much data as the buffer can hold. */ len = sizeof(devc->buf) - devc->buf_len; len = serial_read(serial, devc->buf + devc->buf_len, len); if (len < 1) { sr_err("Serial port read error: %d.", len); return FALSE; } devc->buf_len += len; /* Now look for packets in that data. */ ptr = devc->buf; end_ptr = ptr + devc->buf_len; while ((next_ptr = appa_55ii_parse_data(sdi, ptr, end_ptr - ptr))) ptr = next_ptr; /* If we have any data left, move it to the beginning of our buffer. */ memmove(devc->buf, ptr, end_ptr - ptr); devc->buf_len -= ptr - devc->buf; /* If buffer is full and no valid packet was found, wipe buffer. */ if (devc->buf_len >= sizeof(devc->buf)) { devc->buf_len = 0; return FALSE; } if (devc->limit_samples && devc->num_samples >= devc->limit_samples) { sr_info("Requested number of samples reached."); sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data); return TRUE; } if (devc->limit_msec) { time = (g_get_monotonic_time() - devc->start_time) / 1000; if (time > (int64_t)devc->limit_msec) { sr_info("Requested time limit reached."); sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data); return TRUE; } } return TRUE; } libsigrok-0.3.0/hardware/appa-55ii/api.c0000644000175000017500000001563712332246667014653 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Aurelien Jacobs * * 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 . */ #include #include "protocol.h" static const int32_t hwopts[] = { SR_CONF_CONN, SR_CONF_SERIALCOMM, }; static const int32_t hwcaps[] = { SR_CONF_THERMOMETER, SR_CONF_LIMIT_SAMPLES, SR_CONF_LIMIT_MSEC, SR_CONF_CONTINUOUS, SR_CONF_DATA_SOURCE, }; static const char *data_sources[] = { "Live", "Memory", }; SR_PRIV struct sr_dev_driver appa_55ii_driver_info; static struct sr_dev_driver *di = &appa_55ii_driver_info; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_serial_dev_inst *serial; struct sr_dev_inst *sdi; struct sr_channel *ch; struct sr_config *src; GSList *devices, *l; const char *conn, *serialcomm; uint8_t buf[50]; size_t len; len = sizeof(buf); devices = NULL; conn = serialcomm = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; case SR_CONF_SERIALCOMM: serialcomm = g_variant_get_string(src->data, NULL); break; } } if (!conn) return NULL; if (!serialcomm) serialcomm = "9600/8n1"; if (!(serial = sr_serial_dev_inst_new(conn, serialcomm))) return NULL; if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK) return NULL; sr_info("Probing serial port %s.", conn); drvc = di->priv; drvc->instances = NULL; serial_flush(serial); /* Let's get a bit of data and see if we can find a packet. */ if (serial_stream_detect(serial, buf, &len, 25, appa_55ii_packet_valid, 500, 9600) != SR_OK) goto scan_cleanup; sr_info("Found device on port %s.", conn); if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "APPA", "55II", NULL))) goto scan_cleanup; if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); goto scan_cleanup; } devc->data_source = DEFAULT_DATA_SOURCE; sdi->inst_type = SR_INST_SERIAL; sdi->conn = serial; sdi->priv = devc; sdi->driver = di; if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "T1"))) goto scan_cleanup; sdi->channels = g_slist_append(sdi->channels, ch); if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "T2"))) goto scan_cleanup; sdi->channels = g_slist_append(sdi->channels, ch); drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); scan_cleanup: serial_close(serial); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int cleanup(void) { return std_dev_clear(di, NULL); } static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc = sdi->priv; (void)cg; switch (key) { case SR_CONF_LIMIT_SAMPLES: *data = g_variant_new_uint64(devc->limit_samples); break; case SR_CONF_LIMIT_MSEC: *data = g_variant_new_uint64(devc->limit_msec); break; case SR_CONF_DATA_SOURCE: *data = g_variant_new_string(data_sources[devc->data_source]); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; const char *tmp_str; unsigned int i; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return SR_ERR_BUG; } switch (key) { case SR_CONF_LIMIT_SAMPLES: devc->limit_samples = g_variant_get_uint64(data); sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples); break; case SR_CONF_LIMIT_MSEC: devc->limit_msec = g_variant_get_uint64(data); sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec); break; case SR_CONF_DATA_SOURCE: { tmp_str = g_variant_get_string(data, NULL); for (i = 0; i < ARRAY_SIZE(data_sources); i++) if (!strcmp(tmp_str, data_sources[i])) { devc->data_source = i; break; } if (i == ARRAY_SIZE(data_sources)) return SR_ERR; break; } default: return SR_ERR_NA; } return SR_OK; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; case SR_CONF_DATA_SOURCE: *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources)); break; default: return SR_ERR_NA; } return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct sr_serial_dev_inst *serial; struct dev_context *devc; serial = sdi->conn; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return SR_ERR_BUG; } devc->session_cb_data = cb_data; /* * Reset the number of samples to take. If we've already collected our * quota, but we start a new session, and don't reset this, we'll just * quit without acquiring any new samples. */ devc->num_samples = 0; devc->start_time = g_get_monotonic_time(); /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* Poll every 50ms, or whenever some data comes in. */ serial_source_add(serial, G_IO_IN, 50, appa_55ii_receive_data, (void *)sdi); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close, sdi->conn, LOG_PREFIX); } SR_PRIV struct sr_dev_driver appa_55ii_driver_info = { .name = "appa-55ii", .longname = "APPA 55II", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = std_serial_dev_open, .dev_close = std_serial_dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/tondaj-sl-814/0000755000175000017500000000000012332246734014510 500000000000000libsigrok-0.3.0/hardware/tondaj-sl-814/protocol.h0000644000175000017500000000302112332246667016443 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LIBSIGROK_HARDWARE_TONDAJ_SL_814_PROTOCOL_H #define LIBSIGROK_HARDWARE_TONDAJ_SL_814_PROTOCOL_H #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "tondaj-sl-814" /** Private, per-device-instance driver context. */ struct dev_context { /** The current sampling limit (in number of samples). */ uint64_t limit_samples; /** The current sampling limit (in ms). */ uint64_t limit_msec; /** Opaque pointer passed in by the frontend. */ void *cb_data; /** The current number of already received samples. */ uint64_t num_samples; int state; uint8_t buf[4]; uint8_t buflen; }; SR_PRIV int tondaj_sl_814_receive_data(int fd, int revents, void *cb_data); #endif libsigrok-0.3.0/hardware/tondaj-sl-814/protocol.c0000644000175000017500000001261212332246667016444 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "protocol.h" /* States */ enum { SEND_INIT, GET_INIT_REPLY, SEND_PACKET_REQUEST, GET_PACKET, }; static void parse_packet(const uint8_t *buf, float *floatval, struct sr_datafeed_analog *analog) { gboolean is_a, is_fast; uint16_t intval; uint8_t level = 0, level_bits; /* Byte 0 [7:7]: 0 = A, 1 = C */ is_a = ((buf[0] & (1 << 7)) == 0); /* Byte 0 [6:6]: Unknown/unused? */ /* Byte 0 [5:4]: Level (00 = 40, 01 = 60, 10 = 80, 11 = 100) */ level_bits = (buf[0] >> 4) & 0x03; if (level_bits == 0) level = 40; else if (level_bits == 1) level = 60; else if (level_bits == 2) level = 80; else if (level_bits == 3) level = 100; /* Byte 0 [3:3]: 0 = fast, 1 = slow */ is_fast = ((buf[0] & (1 << 3)) == 0); /* Byte 0 [2:0]: value[10..8] */ /* Byte 1 [7:0]: value[7..0] */ intval = (buf[0] & 0x7) << 8; intval |= buf[1]; *floatval = (float)intval; /* The value on the display always has one digit after the comma. */ *floatval /= 10; analog->mq = SR_MQ_SOUND_PRESSURE_LEVEL; analog->unit = SR_UNIT_DECIBEL_SPL; if (is_a) analog->mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A; else analog->mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C; if (is_fast) analog->mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F; else analog->mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S; /* TODO: How to handle level? */ (void)level; } static void decode_packet(struct sr_dev_inst *sdi) { struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; struct dev_context *devc; float floatval; devc = sdi->priv; memset(&analog, 0, sizeof(struct sr_datafeed_analog)); parse_packet(devc->buf, &floatval, &analog); /* Send a sample packet with one analog value. */ analog.channels = sdi->channels; analog.num_samples = 1; analog.data = &floatval; packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(devc->cb_data, &packet); devc->num_samples++; } int tondaj_sl_814_receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_serial_dev_inst *serial; uint8_t buf[3]; int ret; (void)fd; (void)revents; sdi = cb_data; serial = sdi->conn; devc = sdi->priv; /* TODO: Parts of this code need to be improved later. */ /* State machine. */ if (devc->state == SEND_INIT) { /* On the first run, send the "init" command. */ buf[0] = 0x10; buf[1] = 0x04; buf[2] = 0x0d; sr_spew("Sending init command: %02x %02x %02x.", buf[0], buf[1], buf[2]); if ((ret = serial_write(serial, buf, 3)) < 0) { sr_err("Error sending init command: %d.", ret); return FALSE; } devc->state = GET_INIT_REPLY; } else if (devc->state == GET_INIT_REPLY) { /* If we just sent the "init" command, get its reply. */ if ((ret = serial_read(serial, buf, 2)) < 0) { sr_err("Error reading init reply: %d.", ret); return FALSE; } sr_spew("Received init reply: %02x %02x.", buf[0], buf[1]); /* Expected reply: 0x05 0x0d */ if (buf[0] != 0x05 || buf[1] != 0x0d) { sr_err("Received incorrect init reply, retrying."); devc->state = SEND_INIT; return TRUE; } devc->state = SEND_PACKET_REQUEST; } else if (devc->state == SEND_PACKET_REQUEST) { /* Request a packet (send 0x30 ZZ 0x0d). */ buf[0] = 0x30; buf[1] = 0x00; /* ZZ */ buf[2] = 0x0d; sr_spew("Sending data request command: %02x %02x %02x.", buf[0], buf[1], buf[2]); if ((ret = serial_write(serial, buf, 3)) < 0) { sr_err("Error sending request command: %d.", ret); return FALSE; } devc->buflen = 0; devc->state = GET_PACKET; } else if (devc->state == GET_PACKET) { /* Read a packet from the device. */ ret = serial_read(serial, devc->buf + devc->buflen, 4 - devc->buflen); if (ret < 0) { sr_err("Error reading packet: %d.", ret); return TRUE; } devc->buflen += ret; /* Didn't receive all 4 bytes, yet. */ if (devc->buflen != 4) return TRUE; sr_spew("Received packet: %02x %02x %02x %02x.", devc->buf[0], devc->buf[1], devc->buf[2], devc->buf[3]); /* Expected reply: AA BB ZZ+1 0x0d */ if (devc->buf[2] != 0x01 || devc->buf[3] != 0x0d) { sr_err("Received incorrect request reply, retrying."); devc->state = SEND_PACKET_REQUEST; return TRUE; } decode_packet(sdi); devc->state = SEND_PACKET_REQUEST; } else { sr_err("Invalid state: %d.", devc->state); return FALSE; } /* Stop acquisition if we acquired enough samples. */ if (devc->limit_samples && devc->num_samples >= devc->limit_samples) { sr_info("Requested number of samples reached."); sdi->driver->dev_acquisition_stop(sdi, cb_data); } return TRUE; } libsigrok-0.3.0/hardware/tondaj-sl-814/api.c0000644000175000017500000001235412332246667015357 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "protocol.h" #define SERIALCOMM "9600/8e1" static const int32_t hwopts[] = { SR_CONF_CONN, SR_CONF_SERIALCOMM, }; static const int32_t hwcaps[] = { SR_CONF_SOUNDLEVELMETER, SR_CONF_LIMIT_SAMPLES, SR_CONF_CONTINUOUS, }; SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info; static struct sr_dev_driver *di = &tondaj_sl_814_driver_info; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_config *src; struct sr_channel *ch; GSList *devices, *l; const char *conn, *serialcomm; struct sr_serial_dev_inst *serial; drvc = di->priv; drvc->instances = NULL; devices = NULL; conn = serialcomm = NULL; for (l = options; l; l = l->next) { if (!(src = l->data)) { sr_err("Invalid option data, skipping."); continue; } switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; case SR_CONF_SERIALCOMM: serialcomm = g_variant_get_string(src->data, NULL); break; default: sr_err("Unknown option %d, skipping.", src->key); break; } } if (!conn) return NULL; if (!serialcomm) serialcomm = SERIALCOMM; if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Tondaj", "SL-814", NULL))) { sr_err("Failed to create device instance."); return NULL; } if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } if (!(serial = sr_serial_dev_inst_new(conn, serialcomm))) return NULL; if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return NULL; sdi->inst_type = SR_INST_SERIAL; sdi->conn = serial; sdi->priv = devc; sdi->driver = di; ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1"); if (!ch) { sr_err("Failed to create channel."); return NULL; } sdi->channels = g_slist_append(sdi->channels, ch); drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int cleanup(void) { return std_dev_clear(di, NULL); } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; switch (id) { case SR_CONF_LIMIT_SAMPLES: devc->limit_samples = g_variant_get_uint64(data); sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples); break; default: return SR_ERR_NA; } return SR_OK; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; default: return SR_ERR_NA; } return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct sr_serial_dev_inst *serial; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; devc->cb_data = cb_data; /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* Poll every 500ms, or whenever some data comes in. */ serial = sdi->conn; serial_source_add(serial, G_IO_IN, 500, tondaj_sl_814_receive_data, (void *)sdi); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close, sdi->conn, LOG_PREFIX); } SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info = { .name = "tondaj-sl-814", .longname = "Tondaj SL-814", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = NULL, .config_set = config_set, .config_list = config_list, .dev_open = std_serial_dev_open, .dev_close = std_serial_dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/ikalogic-scanaplus/0000755000175000017500000000000012332246734016054 500000000000000libsigrok-0.3.0/hardware/ikalogic-scanaplus/protocol.h0000644000175000017500000000372012332246667020015 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LIBSIGROK_HARDWARE_IKALOGIC_SCANAPLUS_PROTOCOL_H #define LIBSIGROK_HARDWARE_IKALOGIC_SCANAPLUS_PROTOCOL_H #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "ikalogic-scanaplus" #define COMPRESSED_BUF_SIZE (64 * 1024) /* Private, per-device-instance driver context. */ struct dev_context { /** FTDI device context (used by libftdi). */ struct ftdi_context *ftdic; /** The current sampling limit (in ms). */ uint64_t limit_msec; /** The current sampling limit (in number of samples). */ uint64_t limit_samples; void *cb_data; uint8_t *compressed_buf; uint64_t compressed_bytes_ignored; uint8_t *sample_buf; uint64_t bytes_received; uint64_t samples_sent; /** ScanaPLUS unique device ID (3 bytes). */ uint8_t devid[3]; }; SR_PRIV int scanaplus_close(struct dev_context *devc); SR_PRIV int scanaplus_get_device_id(struct dev_context *devc); SR_PRIV int scanaplus_init(struct dev_context *devc); SR_PRIV int scanaplus_start_acquisition(struct dev_context *devc); SR_PRIV int scanaplus_receive_data(int fd, int revents, void *cb_data); #endif libsigrok-0.3.0/hardware/ikalogic-scanaplus/protocol.c0000644000175000017500000002354312332246667020015 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "protocol.h" /* * Logic level thresholds. * * For each of the two channel groups (1-4 and 5-9), the logic level * threshold can be set independently. * * The threshold can be set to values that are usable for systems with * different voltage levels, e.g. for 1.8V or 3.3V systems. * * The actual threshold value is always the middle of the values below. * E.g. for a system voltage level of 1.8V, the threshold is at 0.9V. That * means that values <= 0.9V are considered to be a logic 0/low, and * values > 0.9V are considered to be a logic 1/high. * * - 1.2V system: threshold = 0.6V * - 1.5V system: threshold = 0.75V * - 1.8V system: threshold = 0.9V * - 2.8V system: threshold = 1.4V * - 3.3V system: threshold = 1.65V */ #define THRESHOLD_1_2V_SYSTEM 0x2e #define THRESHOLD_1_5V_SYSTEM 0x39 #define THRESHOLD_1_8V_SYSTEM 0x45 #define THRESHOLD_2_8V_SYSTEM 0x6c #define THRESHOLD_3_3V_SYSTEM 0x7f static int scanaplus_write(struct dev_context *devc, uint8_t *buf, int size) { int i, bytes_written; GString *s; /* Note: Caller checks devc, devc->ftdic, buf, size. */ s = g_string_sized_new(100); g_string_printf(s, "Writing %d bytes: ", size); for (i = 0; i < size; i++) g_string_append_printf(s, "0x%02x ", buf[i]); sr_spew("%s", s->str); g_string_free(s, TRUE); bytes_written = ftdi_write_data(devc->ftdic, buf, size); if (bytes_written < 0) { sr_err("Failed to write FTDI data (%d): %s.", bytes_written, ftdi_get_error_string(devc->ftdic)); } else if (bytes_written != size) { sr_err("FTDI write error, only %d/%d bytes written: %s.", bytes_written, size, ftdi_get_error_string(devc->ftdic)); } return bytes_written; } SR_PRIV int scanaplus_close(struct dev_context *devc) { int ret; /* Note: Caller checks devc and devc->ftdic. */ if ((ret = ftdi_usb_close(devc->ftdic)) < 0) { sr_err("Failed to close FTDI device (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); return SR_ERR; } return SR_OK; } static void scanaplus_uncompress_block(struct dev_context *devc, uint64_t num_bytes) { uint64_t i, j; uint8_t num_samples, low, high; for (i = 0; i < num_bytes; i += 2) { num_samples = devc->compressed_buf[i + 0] >> 1; low = devc->compressed_buf[i + 0] & (1 << 0); high = devc->compressed_buf[i + 1]; for (j = 0; j < num_samples; j++) { devc->sample_buf[devc->bytes_received++] = high; devc->sample_buf[devc->bytes_received++] = low; } } } static void send_samples(struct dev_context *devc, uint64_t samples_to_send) { struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; sr_spew("Sending %" PRIu64 " samples.", samples_to_send); packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = samples_to_send * 2; logic.unitsize = 2; /* We need 2 bytes for 9 channels. */ logic.data = devc->sample_buf; sr_session_send(devc->cb_data, &packet); devc->samples_sent += samples_to_send; devc->bytes_received -= samples_to_send * 2; } SR_PRIV int scanaplus_get_device_id(struct dev_context *devc) { int ret; uint16_t val1, val2; /* FTDI EEPROM indices 16+17 contain the 3 device ID bytes. */ if ((ret = ftdi_read_eeprom_location(devc->ftdic, 16, &val1)) < 0) { sr_err("Failed to read EEPROM index 16 (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); return SR_ERR; } if ((ret = ftdi_read_eeprom_location(devc->ftdic, 17, &val2)) < 0) { sr_err("Failed to read EEPROM index 17 (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); return SR_ERR; } /* * Note: Bit 7 of the three bytes must not be used, apparently. * * Even though the three bits can be either 0 or 1 (we've seen both * in actual ScanaPLUS devices), the device ID as sent to the FPGA * has bit 7 of each byte zero'd out. * * It is unknown whether bit 7 of these bytes has any meaning, * whether it's used somewhere, or whether it can be simply ignored. */ devc->devid[0] = ((val1 >> 0) & 0xff) & ~(1 << 7); devc->devid[1] = ((val1 >> 8) & 0xff) & ~(1 << 7); devc->devid[2] = ((val2 >> 0) & 0xff) & ~(1 << 7); return SR_OK; } static int scanaplus_clear_device_id(struct dev_context *devc) { uint8_t buf[2]; buf[0] = 0x8c; buf[1] = 0x00; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; buf[0] = 0x8e; buf[1] = 0x00; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; buf[0] = 0x8f; buf[1] = 0x00; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; return SR_OK; } static int scanaplus_send_device_id(struct dev_context *devc) { uint8_t buf[2]; buf[0] = 0x8c; buf[1] = devc->devid[0]; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; buf[0] = 0x8e; buf[1] = devc->devid[1]; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; buf[0] = 0x8f; buf[1] = devc->devid[2]; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; return SR_OK; } SR_PRIV int scanaplus_init(struct dev_context *devc) { int i; uint8_t buf[8]; buf[0] = 0x88; buf[1] = 0x41; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; buf[0] = 0x89; buf[1] = 0x64; buf[2] = 0x8a; buf[3] = 0x64; if (scanaplus_write(devc, (uint8_t *)&buf, 4) < 0) return SR_ERR; buf[0] = 0x88; buf[1] = 0x41; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; buf[0] = 0x88; buf[1] = 0x40; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; buf[0] = 0x8d; buf[1] = 0x01; buf[2] = 0x8d; buf[3] = 0x05; buf[4] = 0x8d; buf[5] = 0x01; buf[6] = 0x8d; buf[7] = 0x02; if (scanaplus_write(devc, (uint8_t *)&buf, 8) < 0) return SR_ERR; for (i = 0; i < 57; i++) { buf[0] = 0x8d; buf[1] = 0x06; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; buf[0] = 0x8d; buf[1] = 0x02; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; } if (scanaplus_send_device_id(devc) < 0) return SR_ERR; buf[0] = 0x88; buf[1] = 0x40; if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; return SR_OK; } SR_PRIV int scanaplus_start_acquisition(struct dev_context *devc) { uint8_t buf[4]; /* Threshold and differential channel settings not yet implemented. */ buf[0] = 0x89; buf[1] = 0x7f; /* Logic level threshold for channels 1-4. */ buf[2] = 0x8a; buf[3] = 0x7f; /* Logic level threshold for channels 5-9. */ if (scanaplus_write(devc, (uint8_t *)&buf, 4) < 0) return SR_ERR; buf[0] = 0x88; buf[1] = 0x40; /* Special config of channels 5/6 and 7/8. */ /* 0x40: normal, 0x50: ch56 diff, 0x48: ch78 diff, 0x58: ch5678 diff */ if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0) return SR_ERR; if (scanaplus_clear_device_id(devc) < 0) return SR_ERR; if (scanaplus_send_device_id(devc) < 0) return SR_ERR; return SR_OK; } SR_PRIV int scanaplus_receive_data(int fd, int revents, void *cb_data) { int bytes_read; struct sr_dev_inst *sdi; struct dev_context *devc; uint64_t max, n; (void)fd; (void)revents; if (!(sdi = cb_data)) return TRUE; if (!(devc = sdi->priv)) return TRUE; if (!devc->ftdic) return TRUE; /* Get a block of data. */ bytes_read = ftdi_read_data(devc->ftdic, devc->compressed_buf, COMPRESSED_BUF_SIZE); if (bytes_read < 0) { sr_err("Failed to read FTDI data (%d): %s.", bytes_read, ftdi_get_error_string(devc->ftdic)); sdi->driver->dev_acquisition_stop(sdi, sdi); return FALSE; } if (bytes_read == 0) { sr_spew("Received 0 bytes, nothing to do."); return TRUE; } /* * After a ScanaPLUS acquisition starts, a bunch of samples will be * returned as all-zero, no matter which signals are actually present * on the channels. This is probably due to the FPGA reconfiguring some * of its internal state/config during this time. * * As far as we know there is apparently no way for the PC-side to * know when this "reconfiguration" starts or ends. The FTDI chip * will return all-zero "dummy" samples during this time, which is * indistinguishable from actual all-zero samples. * * We currently simply ignore the first 64kB of data after an * acquisition starts. Empirical tests have shown that the * "reconfigure" time is a lot less than that usually. */ if (devc->compressed_bytes_ignored < COMPRESSED_BUF_SIZE) { /* Ignore the first 64kB of data of every acquisition. */ sr_spew("Ignoring first 64kB chunk of data."); devc->compressed_bytes_ignored += COMPRESSED_BUF_SIZE; return TRUE; } /* TODO: Handle bytes_read which is not a multiple of 2? */ scanaplus_uncompress_block(devc, bytes_read); n = devc->samples_sent + (devc->bytes_received / 2); max = (SR_MHZ(100) / 1000) * devc->limit_msec; if (devc->limit_samples && (n >= devc->limit_samples)) { send_samples(devc, devc->limit_samples - devc->samples_sent); sr_info("Requested number of samples reached."); sdi->driver->dev_acquisition_stop(sdi, cb_data); return TRUE; } else if (devc->limit_msec && (n >= max)) { send_samples(devc, max - devc->samples_sent); sr_info("Requested time limit reached."); sdi->driver->dev_acquisition_stop(sdi, cb_data); return TRUE; } else { send_samples(devc, devc->bytes_received / 2); } return TRUE; } libsigrok-0.3.0/hardware/ikalogic-scanaplus/api.c0000644000175000017500000002555412332246667016731 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Uwe Hermann * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "protocol.h" #define USB_VENDOR_ID 0x0403 #define USB_DEVICE_ID 0x6014 #define USB_VENDOR_NAME "IKALOGIC" #define USB_MODEL_NAME "ScanaPLUS" #define USB_IPRODUCT "SCANAPLUS" #define SAMPLE_BUF_SIZE (8 * 1024 * 1024) static const int32_t hwcaps[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_SAMPLERATE, SR_CONF_LIMIT_MSEC, SR_CONF_LIMIT_SAMPLES, SR_CONF_CONTINUOUS, // TODO? }; /* Channels are numbered 1-9. */ static const char *channel_names[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL, }; /* Note: The IKALOGIC ScanaPLUS always samples at 100MHz. */ static uint64_t samplerates[1] = { SR_MHZ(100) }; SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info; static struct sr_dev_driver *di = &ikalogic_scanaplus_driver_info; static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data); static void clear_helper(void *priv) { struct dev_context *devc; devc = priv; ftdi_free(devc->ftdic); g_free(devc->compressed_buf); g_free(devc->sample_buf); } static int dev_clear(void) { return std_dev_clear(di, clear_helper); } static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct sr_dev_inst *sdi; struct sr_channel *ch; struct drv_context *drvc; struct dev_context *devc; GSList *devices; unsigned int i; int ret; (void)options; drvc = di->priv; devices = NULL; /* Allocate memory for our private device context. */ if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); goto err_free_nothing; } /* Allocate memory for the incoming compressed samples. */ if (!(devc->compressed_buf = g_try_malloc0(COMPRESSED_BUF_SIZE))) { sr_err("compressed_buf malloc failed."); goto err_free_devc; } /* Allocate memory for the uncompressed samples. */ if (!(devc->sample_buf = g_try_malloc0(SAMPLE_BUF_SIZE))) { sr_err("sample_buf malloc failed."); goto err_free_compressed_buf; } /* Allocate memory for the FTDI context (ftdic) and initialize it. */ if (!(devc->ftdic = ftdi_new())) { sr_err("Failed to initialize libftdi."); goto err_free_sample_buf; } /* Check for the device and temporarily open it. */ ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, USB_DEVICE_ID, USB_IPRODUCT, NULL); if (ret < 0) { /* Log errors, except for -3 ("device not found"). */ if (ret != -3) sr_err("Failed to open device (%d): %s", ret, ftdi_get_error_string(devc->ftdic)); goto err_free_ftdic; } /* Register the device with libsigrok. */ sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING, USB_VENDOR_NAME, USB_MODEL_NAME, NULL); if (!sdi) { sr_err("Failed to create device instance."); goto err_close_ftdic; } sdi->driver = di; sdi->priv = devc; for (i = 0; channel_names[i]; i++) { if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); } devices = g_slist_append(devices, sdi); drvc->instances = g_slist_append(drvc->instances, sdi); /* Close device. We'll reopen it again when we need it. */ scanaplus_close(devc); return devices; err_close_ftdic: scanaplus_close(devc); err_free_ftdic: ftdi_free(devc->ftdic); /* NOT free() or g_free()! */ err_free_sample_buf: g_free(devc->sample_buf); err_free_compressed_buf: g_free(devc->compressed_buf); err_free_devc: g_free(devc); err_free_nothing: return NULL; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; devc = sdi->priv; /* Select interface A, otherwise communication will fail. */ ret = ftdi_set_interface(devc->ftdic, INTERFACE_A); if (ret < 0) { sr_err("Failed to set FTDI interface A (%d): %s", ret, ftdi_get_error_string(devc->ftdic)); return SR_ERR; } sr_dbg("FTDI chip interface A set successfully."); /* Open the device. */ ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, USB_DEVICE_ID, USB_IPRODUCT, NULL); if (ret < 0) { sr_err("Failed to open device (%d): %s", ret, ftdi_get_error_string(devc->ftdic)); return SR_ERR; } sr_dbg("FTDI device opened successfully."); /* Purge RX/TX buffers in the FTDI chip. */ if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) { sr_err("Failed to purge FTDI RX/TX buffers (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); goto err_dev_open_close_ftdic; } sr_dbg("FTDI chip buffers purged successfully."); /* Reset the FTDI bitmode. */ ret = ftdi_set_bitmode(devc->ftdic, 0xff, BITMODE_RESET); if (ret < 0) { sr_err("Failed to reset the FTDI chip bitmode (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); goto err_dev_open_close_ftdic; } sr_dbg("FTDI chip bitmode reset successfully."); /* Set FTDI bitmode to "sync FIFO". */ ret = ftdi_set_bitmode(devc->ftdic, 0xff, BITMODE_SYNCFF); if (ret < 0) { sr_err("Failed to put FTDI chip into sync FIFO mode (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); goto err_dev_open_close_ftdic; } sr_dbg("FTDI chip sync FIFO mode entered successfully."); /* Set the FTDI latency timer to 2. */ ret = ftdi_set_latency_timer(devc->ftdic, 2); if (ret < 0) { sr_err("Failed to set FTDI latency timer (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); goto err_dev_open_close_ftdic; } sr_dbg("FTDI chip latency timer set successfully."); /* Set the FTDI read data chunk size to 64kB. */ ret = ftdi_read_data_set_chunksize(devc->ftdic, 64 * 1024); if (ret < 0) { sr_err("Failed to set FTDI read data chunk size (%d): %s.", ret, ftdi_get_error_string(devc->ftdic)); goto err_dev_open_close_ftdic; } sr_dbg("FTDI chip read data chunk size set successfully."); /* Get the ScanaPLUS device ID from the FTDI EEPROM. */ if ((ret = scanaplus_get_device_id(devc)) < 0) { sr_err("Failed to get ScanaPLUS device ID: %d.", ret); goto err_dev_open_close_ftdic; } sr_dbg("Received ScanaPLUS device ID successfully: %02x %02x %02x.", devc->devid[0], devc->devid[1], devc->devid[2]); sdi->status = SR_ST_ACTIVE; return SR_OK; err_dev_open_close_ftdic: scanaplus_close(devc); return SR_ERR; } static int dev_close(struct sr_dev_inst *sdi) { int ret; struct dev_context *devc; ret = SR_OK; devc = sdi->priv; if (sdi->status == SR_ST_ACTIVE) { sr_dbg("Status ACTIVE, closing device."); ret = scanaplus_close(devc); } else { sr_spew("Status not ACTIVE, nothing to do."); } sdi->status = SR_ST_INACTIVE; return ret; } static int cleanup(void) { return dev_clear(); } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { (void)sdi; (void)cg; switch (id) { case SR_CONF_SAMPLERATE: /* The ScanaPLUS samplerate is 100MHz and can't be changed. */ *data = g_variant_new_uint64(SR_MHZ(100)); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; switch (id) { case SR_CONF_SAMPLERATE: if (g_variant_get_uint64(data) != SR_MHZ(100)) { sr_err("ScanaPLUS only supports samplerate = 100MHz."); return SR_ERR_ARG; } /* Nothing to do, the ScanaPLUS samplerate is always 100MHz. */ break; case SR_CONF_LIMIT_MSEC: if (g_variant_get_uint64(data) == 0) return SR_ERR_ARG; devc->limit_msec = g_variant_get_uint64(data); break; case SR_CONF_LIMIT_SAMPLES: if (g_variant_get_uint64(data) == 0) return SR_ERR_ARG; devc->limit_samples = g_variant_get_uint64(data); break; default: return SR_ERR_NA; } return SR_OK; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { GVariant *gvar; GVariantBuilder gvb; (void)sdi; (void)cg; switch (key) { case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; 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)); g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); *data = g_variant_builder_end(&gvb); break; default: return SR_ERR_NA; } return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { int ret; struct dev_context *devc; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) return SR_ERR_BUG; if (!devc->ftdic) return SR_ERR_BUG; /* TODO: Configure channels later (thresholds etc.). */ devc->cb_data = cb_data; /* Properly reset internal variables before every new acquisition. */ devc->compressed_bytes_ignored = 0; devc->samples_sent = 0; devc->bytes_received = 0; if ((ret = scanaplus_init(devc)) < 0) return ret; if ((ret = scanaplus_start_acquisition(devc)) < 0) return ret; /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* Hook up a dummy handler to receive data from the device. */ sr_source_add(-1, G_IO_IN, 0, scanaplus_receive_data, (void *)sdi); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { struct sr_datafeed_packet packet; (void)sdi; sr_dbg("Stopping acquisition."); sr_source_remove(-1); /* Send end packet to the session bus. */ sr_dbg("Sending SR_DF_END."); packet.type = SR_DF_END; sr_session_send(cb_data, &packet); return SR_OK; } SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info = { .name = "ikalogic-scanaplus", .longname = "IKALOGIC ScanaPLUS", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = dev_clear, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/hantek-dso/0000755000175000017500000000000012332246734014340 500000000000000libsigrok-0.3.0/hardware/hantek-dso/dso.c0000644000175000017500000004661212332246667015227 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * With protocol information from the hantekdso project, * Copyright (C) 2008 Oleg Khudyakov * * 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 . */ #include "libsigrok.h" #include "libsigrok-internal.h" #include "dso.h" #include #include #include extern struct sr_dev_driver hantek_dso_driver_info; static int send_begin(const struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; int ret; unsigned char buffer[] = {0x0f, 0x03, 0x03, 0x03, 0x68, 0xac, 0xfe, 0x00, 0x01, 0x00}; sr_dbg("Sending CTRL_BEGINCOMMAND."); usb = sdi->conn; if ((ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR, CTRL_BEGINCOMMAND, 0, 0, buffer, sizeof(buffer), 200)) != sizeof(buffer)) { sr_err("Failed to send begincommand: %s.", libusb_error_name(ret)); return SR_ERR; } return SR_OK; } static int send_bulkcmd(const struct sr_dev_inst *sdi, uint8_t *cmdstring, int cmdlen) { struct sr_usb_dev_inst *usb; int ret, tmp; usb = sdi->conn; if (send_begin(sdi) != SR_OK) return SR_ERR; if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring, cmdlen, &tmp, 200)) != 0) return SR_ERR; return SR_OK; } static int dso_getmps(libusb_device *dev) { struct libusb_device_descriptor des; struct libusb_config_descriptor *conf_dsc; const struct libusb_interface_descriptor *intf_dsc; int mps; if (libusb_get_device_descriptor(dev, &des) != 0) return 0; if (des.bNumConfigurations != 1) return 0; if (libusb_get_config_descriptor(dev, 0, &conf_dsc) != 0) return 0; mps = 0; intf_dsc = &(conf_dsc->interface[0].altsetting[0]); if (intf_dsc->bNumEndpoints != 2) goto err; if ((intf_dsc->endpoint[0].bEndpointAddress & 0x8f) != (2 | LIBUSB_ENDPOINT_OUT)) /* The first endpoint should be 2 (outbound). */ goto err; if ((intf_dsc->endpoint[1].bEndpointAddress & 0x8f) != (6 | LIBUSB_ENDPOINT_IN)) /* The second endpoint should be 6 (inbound). */ goto err; mps = intf_dsc->endpoint[1].wMaxPacketSize; err: if (conf_dsc) libusb_free_config_descriptor(conf_dsc); return mps; } SR_PRIV int dso_open(struct sr_dev_inst *sdi) { struct dev_context *devc; struct drv_context *drvc = hantek_dso_driver_info.priv; struct sr_usb_dev_inst *usb; struct libusb_device_descriptor des; libusb_device **devlist; int err, skip, i; devc = sdi->priv; usb = sdi->conn; if (sdi->status == SR_ST_ACTIVE) /* already in use */ return SR_ERR; skip = 0; libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if ((err = libusb_get_device_descriptor(devlist[i], &des))) { sr_err("Failed to get device descriptor: %s.", libusb_error_name(err)); continue; } if (des.idVendor != devc->profile->fw_vid || des.idProduct != devc->profile->fw_pid) continue; if (sdi->status == SR_ST_INITIALIZING) { if (skip != sdi->index) { /* Skip devices of this type that aren't the one we want. */ skip += 1; continue; } } else if (sdi->status == SR_ST_INACTIVE) { /* * This device is fully enumerated, so we need to find * this device by vendor, product, bus and address. */ if (libusb_get_bus_number(devlist[i]) != usb->bus || libusb_get_device_address(devlist[i]) != usb->address) /* this is not the one */ continue; } if (!(err = libusb_open(devlist[i], &usb->devhdl))) { if (usb->address == 0xff) /* * first time we touch this device after firmware upload, * so we don't know the address yet. */ usb->address = libusb_get_device_address(devlist[i]); if (!(devc->epin_maxpacketsize = dso_getmps(devlist[i]))) sr_err("Wrong endpoint profile."); else { sdi->status = SR_ST_ACTIVE; sr_info("Opened device %d on %d.%d interface %d.", sdi->index, usb->bus, usb->address, USB_INTERFACE); } } else { sr_err("Failed to open device: %s.", libusb_error_name(err)); } /* If we made it here, we handled the device (somehow). */ break; } libusb_free_device_list(devlist, 1); if (sdi->status != SR_ST_ACTIVE) return SR_ERR; return SR_OK; } SR_PRIV void dso_close(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; usb = sdi->conn; if (usb->devhdl == NULL) return; sr_info("Closing device %d on %d.%d interface %d.", sdi->index, usb->bus, usb->address, USB_INTERFACE); libusb_release_interface(usb->devhdl, USB_INTERFACE); libusb_close(usb->devhdl); usb->devhdl = NULL; sdi->status = SR_ST_INACTIVE; } static int get_channel_offsets(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; GString *gs; int chan, v, ret; sr_dbg("Getting channel offsets."); devc = sdi->priv; usb = sdi->conn; ret = libusb_control_transfer(usb->devhdl, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR, CTRL_READ_EEPROM, EEPROM_CHANNEL_OFFSETS, 0, (unsigned char *)&devc->channel_levels, sizeof(devc->channel_levels), 200); if (ret != sizeof(devc->channel_levels)) { sr_err("Failed to get channel offsets: %s.", libusb_error_name(ret)); return SR_ERR; } /* Comes in as 16-bit numbers with the second byte always 0 on * the DSO-2090. Guessing this is supposed to be big-endian, * since that's how voltage offsets are submitted back to the DSO. * Convert to host order now, so we can use them natively. */ for (chan = 0; chan < 2; chan++) { for (v = 0; v < 9; v++) { devc->channel_levels[chan][v][0] = g_ntohs(devc->channel_levels[chan][v][0]); devc->channel_levels[chan][v][1] = g_ntohs(devc->channel_levels[chan][v][1]); } } if (sr_log_loglevel_get() >= SR_LOG_DBG) { gs = g_string_sized_new(128); for (chan = 0; chan < 2; chan++) { g_string_printf(gs, "CH%d:", chan + 1); for (v = 0; v < 9; v++) { g_string_append_printf(gs, " %.4x-%.4x", devc->channel_levels[chan][v][0], devc->channel_levels[chan][v][1]); } sr_dbg("%s", gs->str); } g_string_free(gs, TRUE); } return SR_OK; } static int dso_set_trigger_samplerate(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; int ret, tmp; uint8_t cmdstring[12]; uint16_t timebase_small[] = { 0xffff, 0xfffc, 0xfff7, 0xffe8, 0xffce, 0xff9c, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79, 0xd8f1 }; uint16_t timebase_large[] = { 0xffff, 0x0000, 0xfffc, 0xfff7, 0xffe8, 0xffce, 0xff9d, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79 }; sr_dbg("Preparing CMD_SET_TRIGGER_SAMPLERATE."); devc = sdi->priv; usb = sdi->conn; memset(cmdstring, 0, sizeof(cmdstring)); /* Command */ cmdstring[0] = CMD_SET_TRIGGER_SAMPLERATE; /* Trigger source */ sr_dbg("Trigger source %s.", devc->triggersource); if (!strcmp("CH2", devc->triggersource)) tmp = 0; else if (!strcmp("CH1", devc->triggersource)) tmp = 1; else if (!strcmp("EXT", devc->triggersource)) tmp = 2; else { sr_err("Invalid trigger source: '%s'.", devc->triggersource); return SR_ERR_ARG; } cmdstring[2] = tmp; /* Frame size */ sr_dbg("Frame size: %d.", devc->framesize); cmdstring[2] |= (devc->framesize == FRAMESIZE_SMALL ? 0x01 : 0x02) << 2; /* Timebase fast */ sr_dbg("Time base index: %d.", devc->timebase); if (devc->framesize == FRAMESIZE_SMALL) { if (devc->timebase < TIME_20us) tmp = 0; else if (devc->timebase == TIME_20us) tmp = 1; else if (devc->timebase == TIME_40us) tmp = 2; else if (devc->timebase == TIME_100us) tmp = 3; else if (devc->timebase >= TIME_200us) tmp = 4; } else { if (devc->timebase < TIME_40us) { sr_err("Timebase < 40us only supported with 10K buffer."); return SR_ERR_ARG; } else if (devc->timebase == TIME_40us) tmp = 0; else if (devc->timebase == TIME_100us) tmp = 2; else if (devc->timebase == TIME_200us) tmp = 3; else if (devc->timebase >= TIME_400us) tmp = 4; } cmdstring[2] |= (tmp & 0x07) << 5; /* Enabled channels: 00=CH1 01=CH2 10=both */ sr_dbg("Channels CH1=%d CH2=%d", devc->ch1_enabled, devc->ch2_enabled); tmp = (((devc->ch2_enabled ? 1 : 0) << 1) + (devc->ch1_enabled ? 1 : 0)) - 1; cmdstring[3] = tmp; /* Fast rates channel */ /* TODO: Is this right? */ tmp = devc->timebase < TIME_10us ? 1 : 0; cmdstring[3] |= tmp << 2; /* Trigger slope: 0=positive 1=negative */ /* TODO: Does this work? */ sr_dbg("Trigger slope: %d.", devc->triggerslope); cmdstring[3] |= (devc->triggerslope == SLOPE_NEGATIVE ? 1 : 0) << 3; /* Timebase slow */ if (devc->timebase < TIME_100us) tmp = 0; else if (devc->timebase > TIME_400ms) tmp = 0xffed; else { if (devc->framesize == FRAMESIZE_SMALL) tmp = timebase_small[devc->timebase - 3]; else tmp = timebase_large[devc->timebase - 3]; } cmdstring[4] = tmp & 0xff; cmdstring[5] = (tmp >> 8) & 0xff; /* Horizontal trigger position */ sr_dbg("Trigger position: %3.2f.", devc->triggerposition); tmp = 0x77fff + 0x8000 * devc->triggerposition; cmdstring[6] = tmp & 0xff; cmdstring[7] = (tmp >> 8) & 0xff; cmdstring[10] = (tmp >> 16) & 0xff; if (send_begin(sdi) != SR_OK) return SR_ERR; if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) { sr_err("Failed to set trigger/samplerate: %s.", libusb_error_name(ret)); return SR_ERR; } sr_dbg("Sent CMD_SET_TRIGGER_SAMPLERATE."); return SR_OK; } static int dso_set_filters(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; int ret, tmp; uint8_t cmdstring[8]; sr_dbg("Preparing CMD_SET_FILTERS."); devc = sdi->priv; usb = sdi->conn; memset(cmdstring, 0, sizeof(cmdstring)); cmdstring[0] = CMD_SET_FILTERS; cmdstring[1] = 0x0f; if (devc->filter_ch1) { sr_dbg("Turning on CH1 filter."); cmdstring[2] |= 0x80; } if (devc->filter_ch2) { sr_dbg("Turning on CH2 filter."); cmdstring[2] |= 0x40; } if (devc->filter_trigger) { /* TODO: supported on the DSO-2090? */ sr_dbg("Turning on trigger filter."); cmdstring[2] |= 0x20; } if (send_begin(sdi) != SR_OK) return SR_ERR; if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) { sr_err("Failed to set filters: %s.", libusb_error_name(ret)); return SR_ERR; } sr_dbg("Sent CMD_SET_FILTERS."); return SR_OK; } static int dso_set_voltage(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; int ret, tmp; uint8_t cmdstring[8]; sr_dbg("Preparing CMD_SET_VOLTAGE."); devc = sdi->priv; usb = sdi->conn; memset(cmdstring, 0, sizeof(cmdstring)); cmdstring[0] = CMD_SET_VOLTAGE; cmdstring[1] = 0x0f; cmdstring[2] = 0x30; /* CH1 volts/div is encoded in bits 0-1 */ sr_dbg("CH1 vdiv index: %d.", devc->voltage_ch1); switch (devc->voltage_ch1) { case VDIV_1V: case VDIV_100MV: case VDIV_10MV: cmdstring[2] |= 0x00; break; case VDIV_2V: case VDIV_200MV: case VDIV_20MV: cmdstring[2] |= 0x01; break; case VDIV_5V: case VDIV_500MV: case VDIV_50MV: cmdstring[2] |= 0x02; break; } /* CH2 volts/div is encoded in bits 2-3 */ sr_dbg("CH2 vdiv index: %d.", devc->voltage_ch2); switch (devc->voltage_ch2) { case VDIV_1V: case VDIV_100MV: case VDIV_10MV: cmdstring[2] |= 0x00; break; case VDIV_2V: case VDIV_200MV: case VDIV_20MV: cmdstring[2] |= 0x04; break; case VDIV_5V: case VDIV_500MV: case VDIV_50MV: cmdstring[2] |= 0x08; break; } if (send_begin(sdi) != SR_OK) return SR_ERR; if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) { sr_err("Failed to set voltage: %s.", libusb_error_name(ret)); return SR_ERR; } sr_dbg("Sent CMD_SET_VOLTAGE."); return SR_OK; } static int dso_set_relays(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; GString *gs; int ret, i; uint8_t relays[17] = { 0x00, 0x04, 0x08, 0x02, 0x20, 0x40, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; sr_dbg("Preparing CTRL_SETRELAYS."); devc = sdi->priv; usb = sdi->conn; if (devc->voltage_ch1 < VDIV_1V) relays[1] = ~relays[1]; if (devc->voltage_ch1 < VDIV_100MV) relays[2] = ~relays[2]; sr_dbg("CH1 coupling: %d.", devc->coupling_ch1); if (devc->coupling_ch1 != COUPLING_AC) relays[3] = ~relays[3]; if (devc->voltage_ch2 < VDIV_1V) relays[4] = ~relays[4]; if (devc->voltage_ch2 < VDIV_100MV) relays[5] = ~relays[5]; sr_dbg("CH2 coupling: %d.", devc->coupling_ch1); if (devc->coupling_ch2 != COUPLING_AC) relays[6] = ~relays[6]; if (!strcmp(devc->triggersource, "EXT")) relays[7] = ~relays[7]; if (sr_log_loglevel_get() >= SR_LOG_DBG) { gs = g_string_sized_new(128); g_string_printf(gs, "Relays:"); for (i = 0; i < 17; i++) g_string_append_printf(gs, " %.2x", relays[i]); sr_dbg("%s", gs->str); g_string_free(gs, TRUE); } if ((ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETRELAYS, 0, 0, relays, 17, 100)) != sizeof(relays)) { sr_err("Failed to set relays: %s.", libusb_error_name(ret)); return SR_ERR; } sr_dbg("Sent CTRL_SETRELAYS."); return SR_OK; } static int dso_set_voffsets(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; int offset, ret; uint16_t *ch_levels; uint8_t offsets[17]; sr_dbg("Preparing CTRL_SETOFFSET."); devc = sdi->priv; usb = sdi->conn; memset(offsets, 0, sizeof(offsets)); /* Channel 1 */ ch_levels = devc->channel_levels[0][devc->voltage_ch1]; offset = (ch_levels[1] - ch_levels[0]) * devc->voffset_ch1 + ch_levels[0]; offsets[0] = (offset >> 8) | 0x20; offsets[1] = offset & 0xff; sr_dbg("CH1 offset: %3.2f (%.2x%.2x).", devc->voffset_ch1, offsets[0], offsets[1]); /* Channel 2 */ ch_levels = devc->channel_levels[1][devc->voltage_ch2]; offset = (ch_levels[1] - ch_levels[0]) * devc->voffset_ch2 + ch_levels[0]; offsets[2] = (offset >> 8) | 0x20; offsets[3] = offset & 0xff; sr_dbg("CH2 offset: %3.2f (%.2x%.2x).", devc->voffset_ch2, offsets[2], offsets[3]); /* Trigger */ offset = MAX_VERT_TRIGGER * devc->voffset_trigger; offsets[4] = (offset >> 8) | 0x20; offsets[5] = offset & 0xff; sr_dbg("Trigger offset: %3.2f (%.2x%.2x).", devc->voffset_trigger, offsets[4], offsets[5]); if ((ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETOFFSET, 0, 0, offsets, sizeof(offsets), 100)) != sizeof(offsets)) { sr_err("Failed to set offsets: %s.", libusb_error_name(ret)); return SR_ERR; } sr_dbg("Sent CTRL_SETOFFSET."); return SR_OK; } SR_PRIV int dso_enable_trigger(const struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; int ret, tmp; uint8_t cmdstring[2]; sr_dbg("Sending CMD_ENABLE_TRIGGER."); usb = sdi->conn; memset(cmdstring, 0, sizeof(cmdstring)); cmdstring[0] = CMD_ENABLE_TRIGGER; cmdstring[1] = 0x00; if (send_begin(sdi) != SR_OK) return SR_ERR; if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) { sr_err("Failed to enable trigger: %s.", libusb_error_name(ret)); return SR_ERR; } return SR_OK; } SR_PRIV int dso_force_trigger(const struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; int ret, tmp; uint8_t cmdstring[2]; sr_dbg("Sending CMD_FORCE_TRIGGER."); usb = sdi->conn; memset(cmdstring, 0, sizeof(cmdstring)); cmdstring[0] = CMD_FORCE_TRIGGER; cmdstring[1] = 0x00; if (send_begin(sdi) != SR_OK) return SR_ERR; if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) { sr_err("Failed to force trigger: %s.", libusb_error_name(ret)); return SR_ERR; } return SR_OK; } SR_PRIV int dso_init(const struct sr_dev_inst *sdi) { sr_dbg("Initializing DSO."); if (get_channel_offsets(sdi) != SR_OK) return SR_ERR; if (dso_set_trigger_samplerate(sdi) != SR_OK) return SR_ERR; if (dso_set_filters(sdi) != SR_OK) return SR_ERR; if (dso_set_voltage(sdi) != SR_OK) return SR_ERR; if (dso_set_relays(sdi) != SR_OK) return SR_ERR; if (dso_set_voffsets(sdi) != SR_OK) return SR_ERR; if (dso_enable_trigger(sdi) != SR_OK) return SR_ERR; return SR_OK; } SR_PRIV int dso_get_capturestate(const struct sr_dev_inst *sdi, uint8_t *capturestate, uint32_t *trigger_offset) { struct sr_usb_dev_inst *usb; int ret, tmp, i; unsigned int bitvalue, toff; uint8_t cmdstring[2], inbuf[512]; sr_dbg("Sending CMD_GET_CAPTURESTATE."); usb = sdi->conn; cmdstring[0] = CMD_GET_CAPTURESTATE; cmdstring[1] = 0; if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) { sr_dbg("Failed to send get_capturestate command: %s.", libusb_error_name(ret)); return SR_ERR; } if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_IN, inbuf, 512, &tmp, 100)) != 0) { sr_dbg("Failed to get capturestate: %s.", libusb_error_name(ret)); return SR_ERR; } *capturestate = inbuf[0]; toff = (inbuf[1] << 16) | (inbuf[3] << 8) | inbuf[2]; /* * This conversion comes from the openhantek project. * Each set bit in the 24-bit value inverts all bits with a lower * value. No idea why the device reports the trigger point this way. */ bitvalue = 1; for (i = 0; i < 24; i++) { /* Each set bit inverts all bits with a lower value. */ if(toff & bitvalue) toff ^= bitvalue - 1; bitvalue <<= 1; } *trigger_offset = toff; return SR_OK; } SR_PRIV int dso_capture_start(const struct sr_dev_inst *sdi) { int ret; uint8_t cmdstring[2]; sr_dbg("Sending CMD_CAPTURE_START."); cmdstring[0] = CMD_CAPTURE_START; cmdstring[1] = 0; if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) { sr_err("Failed to send capture_start command: %s.", libusb_error_name(ret)); return SR_ERR; } return SR_OK; } SR_PRIV int dso_get_channeldata(const struct sr_dev_inst *sdi, libusb_transfer_cb_fn cb) { struct dev_context *devc; struct sr_usb_dev_inst *usb; struct libusb_transfer *transfer; int num_transfers, ret, i; uint8_t cmdstring[2]; unsigned char *buf; sr_dbg("Sending CMD_GET_CHANNELDATA."); devc = sdi->priv; usb = sdi->conn; cmdstring[0] = CMD_GET_CHANNELDATA; cmdstring[1] = 0; if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) { sr_err("Failed to get channel data: %s.", libusb_error_name(ret)); return SR_ERR; } /* TODO: DSO-2xxx only. */ num_transfers = devc->framesize * sizeof(unsigned short) / devc->epin_maxpacketsize; sr_dbg("Queueing up %d transfers.", num_transfers); for (i = 0; i < num_transfers; i++) { if (!(buf = g_try_malloc(devc->epin_maxpacketsize))) { sr_err("Failed to malloc USB endpoint buffer."); return SR_ERR_MALLOC; } transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, usb->devhdl, DSO_EP_IN, buf, devc->epin_maxpacketsize, cb, (void *)sdi, 40); if ((ret = libusb_submit_transfer(transfer)) != 0) { sr_err("Failed to submit transfer: %s.", libusb_error_name(ret)); /* TODO: Free them all. */ libusb_free_transfer(transfer); g_free(buf); return SR_ERR; } } return SR_OK; } libsigrok-0.3.0/hardware/hantek-dso/api.c0000644000175000017500000006123612332246667015212 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "dso.h" /* Max time in ms before we want to check on USB events */ /* TODO tune this properly */ #define TICK 1 #define NUM_TIMEBASE 10 #define NUM_VDIV 8 static const int32_t scanopts[] = { SR_CONF_CONN, }; static const int32_t devopts[] = { SR_CONF_OSCILLOSCOPE, SR_CONF_LIMIT_FRAMES, SR_CONF_CONTINUOUS, SR_CONF_TIMEBASE, SR_CONF_BUFFERSIZE, SR_CONF_TRIGGER_SOURCE, SR_CONF_TRIGGER_SLOPE, SR_CONF_HORIZ_TRIGGERPOS, SR_CONF_FILTER, SR_CONF_VDIV, SR_CONF_COUPLING, SR_CONF_NUM_TIMEBASE, SR_CONF_NUM_VDIV, }; static const char *channel_names[] = { "CH1", "CH2", NULL, }; static const uint64_t buffersizes_32k[] = { 10240, 32768, }; static const uint64_t buffersizes_512k[] = { 10240, 524288, }; static const uint64_t buffersizes_14k[] = { 10240, 14336, }; static const struct dso_profile dev_profiles[] = { { 0x04b4, 0x2090, 0x04b5, 0x2090, "Hantek", "DSO-2090", buffersizes_32k, FIRMWARE_DIR "/hantek-dso-2090.fw" }, { 0x04b4, 0x2150, 0x04b5, 0x2150, "Hantek", "DSO-2150", buffersizes_32k, FIRMWARE_DIR "/hantek-dso-2150.fw" }, { 0x04b4, 0x2250, 0x04b5, 0x2250, "Hantek", "DSO-2250", buffersizes_512k, FIRMWARE_DIR "/hantek-dso-2250.fw" }, { 0x04b4, 0x5200, 0x04b5, 0x5200, "Hantek", "DSO-5200", buffersizes_14k, FIRMWARE_DIR "/hantek-dso-5200.fw" }, { 0x04b4, 0x520a, 0x04b5, 0x520a, "Hantek", "DSO-5200A", buffersizes_512k, FIRMWARE_DIR "/hantek-dso-5200A.fw" }, { 0, 0, 0, 0, 0, 0, 0, 0 }, }; static const uint64_t timebases[][2] = { /* microseconds */ { 10, 1000000 }, { 20, 1000000 }, { 40, 1000000 }, { 100, 1000000 }, { 200, 1000000 }, { 400, 1000000 }, /* milliseconds */ { 1, 1000 }, { 2, 1000 }, { 4, 1000 }, { 10, 1000 }, { 20, 1000 }, { 40, 1000 }, { 100, 1000 }, { 200, 1000 }, { 400, 1000 }, }; static const uint64_t vdivs[][2] = { /* millivolts */ { 10, 1000 }, { 20, 1000 }, { 50, 1000 }, { 100, 1000 }, { 200, 1000 }, { 500, 1000 }, /* volts */ { 1, 1 }, { 2, 1 }, { 5, 1 }, }; static const char *trigger_sources[] = { "CH1", "CH2", "EXT", /* TODO: forced */ }; static const char *filter_targets[] = { "CH1", "CH2", /* TODO: "TRIGGER", */ }; static const char *coupling[] = { "AC", "DC", "GND", }; SR_PRIV struct sr_dev_driver hantek_dso_driver_info; static struct sr_dev_driver *di = &hantek_dso_driver_info; static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data); static struct sr_dev_inst *dso_dev_new(int index, const struct dso_profile *prof) { struct sr_dev_inst *sdi; struct sr_channel *ch; struct drv_context *drvc; struct dev_context *devc; int i; sdi = sr_dev_inst_new(index, SR_ST_INITIALIZING, prof->vendor, prof->model, NULL); if (!sdi) return NULL; sdi->driver = di; /* * Add only the real channels -- EXT isn't a source of data, only * a trigger source internal to the device. */ for (i = 0; channel_names[i]; i++) { if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, channel_names[i]))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); } if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } devc->profile = prof; devc->dev_state = IDLE; devc->timebase = DEFAULT_TIMEBASE; devc->ch1_enabled = TRUE; devc->ch2_enabled = TRUE; devc->voltage_ch1 = DEFAULT_VOLTAGE; devc->voltage_ch2 = DEFAULT_VOLTAGE; devc->coupling_ch1 = DEFAULT_COUPLING; devc->coupling_ch2 = DEFAULT_COUPLING; devc->voffset_ch1 = DEFAULT_VERT_OFFSET; devc->voffset_ch2 = DEFAULT_VERT_OFFSET; devc->voffset_trigger = DEFAULT_VERT_TRIGGERPOS; devc->framesize = DEFAULT_FRAMESIZE; devc->triggerslope = SLOPE_POSITIVE; devc->triggersource = g_strdup(DEFAULT_TRIGGER_SOURCE); devc->triggerposition = DEFAULT_HORIZ_TRIGGERPOS; sdi->priv = devc; drvc = di->priv; drvc->instances = g_slist_append(drvc->instances, sdi); return sdi; } static int configure_channels(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_channel *ch; const GSList *l; int p; devc = sdi->priv; g_slist_free(devc->enabled_channels); devc->ch1_enabled = devc->ch2_enabled = FALSE; for (l = sdi->channels, p = 0; l; l = l->next, p++) { ch = l->data; if (p == 0) devc->ch1_enabled = ch->enabled; else devc->ch2_enabled = ch->enabled; if (ch->enabled) devc->enabled_channels = g_slist_append(devc->enabled_channels, ch); } return SR_OK; } static void clear_dev_context(void *priv) { struct dev_context *devc; devc = priv; g_free(devc->triggersource); g_slist_free(devc->enabled_channels); } static int dev_clear(void) { return std_dev_clear(di, clear_dev_context); } static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_usb_dev_inst *usb; struct sr_config *src; const struct dso_profile *prof; GSList *l, *devices, *conn_devices; struct libusb_device_descriptor des; libusb_device **devlist; int devcnt, ret, i, j; const char *conn; drvc = di->priv; devcnt = 0; devices = 0; conn = NULL; for (l = options; l; l = l->next) { src = l->data; if (src->key == SR_CONF_CONN) { conn = g_variant_get_string(src->data, NULL); break; } } if (conn) conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); else conn_devices = NULL; /* Find all Hantek DSO devices and upload firmware to all of them. */ libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if (conn) { usb = NULL; for (l = conn_devices; l; l = l->next) { usb = l->data; if (usb->bus == libusb_get_bus_number(devlist[i]) && usb->address == libusb_get_device_address(devlist[i])) break; } if (!l) /* This device matched none of the ones that * matched the conn specification. */ continue; } if ((ret = libusb_get_device_descriptor(devlist[i], &des))) { sr_err("Failed to get device descriptor: %s.", libusb_error_name(ret)); continue; } prof = NULL; for (j = 0; dev_profiles[j].orig_vid; j++) { if (des.idVendor == dev_profiles[j].orig_vid && des.idProduct == dev_profiles[j].orig_pid) { /* Device matches the pre-firmware profile. */ prof = &dev_profiles[j]; sr_dbg("Found a %s %s.", prof->vendor, prof->model); sdi = dso_dev_new(devcnt, prof); devices = g_slist_append(devices, sdi); devc = sdi->priv; if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, prof->firmware) == SR_OK) /* Remember when the firmware on this device was updated */ devc->fw_updated = g_get_monotonic_time(); else sr_err("Firmware upload failed for " "device %d.", devcnt); /* Dummy USB address of 0xff will get overwritten later. */ sdi->conn = sr_usb_dev_inst_new( libusb_get_bus_number(devlist[i]), 0xff, NULL); devcnt++; break; } else if (des.idVendor == dev_profiles[j].fw_vid && des.idProduct == dev_profiles[j].fw_pid) { /* Device matches the post-firmware profile. */ prof = &dev_profiles[j]; sr_dbg("Found a %s %s.", prof->vendor, prof->model); sdi = dso_dev_new(devcnt, prof); sdi->status = SR_ST_INACTIVE; devices = g_slist_append(devices, sdi); devc = sdi->priv; sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new( libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); devcnt++; break; } } if (!prof) /* not a supported VID/PID */ continue; } libusb_free_device_list(devlist, 1); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; int64_t timediff_us, timediff_ms; int err; devc = sdi->priv; usb = sdi->conn; /* * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS * for the FX2 to renumerate. */ err = SR_ERR; if (devc->fw_updated > 0) { sr_info("Waiting for device to reset."); /* Takes >= 300ms for the FX2 to be gone from the USB bus. */ g_usleep(300 * 1000); timediff_ms = 0; while (timediff_ms < MAX_RENUM_DELAY_MS) { if ((err = dso_open(sdi)) == SR_OK) break; g_usleep(100 * 1000); timediff_us = g_get_monotonic_time() - devc->fw_updated; timediff_ms = timediff_us / 1000; sr_spew("Waited %" PRIi64 " ms.", timediff_ms); } sr_info("Device came back after %d ms.", timediff_ms); } else { err = dso_open(sdi); } if (err != SR_OK) { sr_err("Unable to open device."); return SR_ERR; } err = libusb_claim_interface(usb->devhdl, USB_INTERFACE); if (err != 0) { sr_err("Unable to claim interface: %s.", libusb_error_name(err)); return SR_ERR; } return SR_OK; } static int dev_close(struct sr_dev_inst *sdi) { dso_close(sdi); return SR_OK; } static int cleanup(void) { return dev_clear(); } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct sr_usb_dev_inst *usb; char str[128]; (void)cg; switch (id) { case SR_CONF_CONN: if (!sdi || !sdi->conn) return SR_ERR_ARG; usb = sdi->conn; if (usb->address == 255) /* Device still needs to re-enumerate after firmware * upload, so we don't know its (future) address. */ return SR_ERR; snprintf(str, 128, "%d.%d", usb->bus, usb->address); *data = g_variant_new_string(str); break; case SR_CONF_NUM_TIMEBASE: *data = g_variant_new_int32(NUM_TIMEBASE); break; case SR_CONF_NUM_VDIV: *data = g_variant_new_int32(NUM_VDIV); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; double tmp_double; uint64_t tmp_u64, p, q; int tmp_int, ret; unsigned int i; const char *tmp_str; char **targets; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; ret = SR_OK; devc = sdi->priv; switch (id) { case SR_CONF_LIMIT_FRAMES: devc->limit_frames = g_variant_get_uint64(data); break; case SR_CONF_TRIGGER_SLOPE: tmp_str = g_variant_get_string(data, NULL); if (!tmp_str || !(tmp_str[0] == 'f' || tmp_str[0] == 'r')) return SR_ERR_ARG; devc->triggerslope = (tmp_str[0] == 'r') ? SLOPE_POSITIVE : SLOPE_NEGATIVE; break; case SR_CONF_HORIZ_TRIGGERPOS: tmp_double = g_variant_get_double(data); if (tmp_double < 0.0 || tmp_double > 1.0) { sr_err("Trigger position should be between 0.0 and 1.0."); ret = SR_ERR_ARG; } else devc->triggerposition = tmp_double; break; case SR_CONF_BUFFERSIZE: tmp_u64 = g_variant_get_uint64(data); for (i = 0; i < 2; i++) { if (devc->profile->buffersizes[i] == tmp_u64) { devc->framesize = tmp_u64; break; } } if (i == 2) ret = SR_ERR_ARG; break; case SR_CONF_TIMEBASE: g_variant_get(data, "(tt)", &p, &q); tmp_int = -1; for (i = 0; i < ARRAY_SIZE(timebases); i++) { if (timebases[i][0] == p && timebases[i][1] == q) { tmp_int = i; break; } } if (tmp_int >= 0) devc->timebase = tmp_int; else ret = SR_ERR_ARG; break; case SR_CONF_TRIGGER_SOURCE: tmp_str = g_variant_get_string(data, NULL); for (i = 0; trigger_sources[i]; i++) { if (!strcmp(tmp_str, trigger_sources[i])) { devc->triggersource = g_strdup(tmp_str); break; } } if (trigger_sources[i] == 0) ret = SR_ERR_ARG; break; case SR_CONF_FILTER: tmp_str = g_variant_get_string(data, NULL); devc->filter_ch1 = devc->filter_ch2 = devc->filter_trigger = 0; targets = g_strsplit(tmp_str, ",", 0); for (i = 0; targets[i]; i++) { if (targets[i] == '\0') /* Empty filter string can be used to clear them all. */ ; else if (!strcmp(targets[i], "CH1")) devc->filter_ch1 = TRUE; else if (!strcmp(targets[i], "CH2")) devc->filter_ch2 = TRUE; else if (!strcmp(targets[i], "TRIGGER")) devc->filter_trigger = TRUE; else { sr_err("Invalid filter target %s.", targets[i]); ret = SR_ERR_ARG; } } g_strfreev(targets); break; case SR_CONF_VDIV: /* TODO: Not supporting vdiv per channel yet. */ g_variant_get(data, "(tt)", &p, &q); tmp_int = -1; for (i = 0; i < ARRAY_SIZE(vdivs); i++) { if (vdivs[i][0] == p && vdivs[i][1] == q) { tmp_int = i; break; } } if (tmp_int >= 0) { devc->voltage_ch1 = tmp_int; devc->voltage_ch2 = tmp_int; } else ret = SR_ERR_ARG; break; case SR_CONF_COUPLING: tmp_str = g_variant_get_string(data, NULL); /* TODO: Not supporting coupling per channel yet. */ for (i = 0; coupling[i]; i++) { if (!strcmp(tmp_str, coupling[i])) { devc->coupling_ch1 = i; devc->coupling_ch2 = i; break; } } if (coupling[i] == 0) ret = SR_ERR_ARG; break; default: ret = SR_ERR_NA; break; } return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; GVariant *tuple, *rational[2]; GVariantBuilder gvb; unsigned int i; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, devopts, ARRAY_SIZE(devopts), sizeof(int32_t)); break; case SR_CONF_BUFFERSIZE: if (!sdi) return SR_ERR_ARG; devc = sdi->priv; *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT64, devc->profile->buffersizes, 2, sizeof(uint64_t)); break; case SR_CONF_COUPLING: *data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling)); break; case SR_CONF_VDIV: g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); for (i = 0; i < ARRAY_SIZE(vdivs); i++) { rational[0] = g_variant_new_uint64(vdivs[i][0]); rational[1] = g_variant_new_uint64(vdivs[i][1]); tuple = g_variant_new_tuple(rational, 2); g_variant_builder_add_value(&gvb, tuple); } *data = g_variant_builder_end(&gvb); break; case SR_CONF_FILTER: *data = g_variant_new_strv(filter_targets, ARRAY_SIZE(filter_targets)); break; case SR_CONF_TIMEBASE: g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); for (i = 0; i < ARRAY_SIZE(timebases); i++) { rational[0] = g_variant_new_uint64(timebases[i][0]); rational[1] = g_variant_new_uint64(timebases[i][1]); tuple = g_variant_new_tuple(rational, 2); g_variant_builder_add_value(&gvb, tuple); } *data = g_variant_builder_end(&gvb); break; case SR_CONF_TRIGGER_SOURCE: *data = g_variant_new_strv(trigger_sources, ARRAY_SIZE(trigger_sources)); break; default: return SR_ERR_NA; } return SR_OK; } static void send_chunk(struct sr_dev_inst *sdi, unsigned char *buf, int num_samples) { struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; struct dev_context *devc; float ch1, ch2, range; int num_channels, data_offset, i; devc = sdi->priv; num_channels = (devc->ch1_enabled && devc->ch2_enabled) ? 2 : 1; packet.type = SR_DF_ANALOG; packet.payload = &analog; /* TODO: support for 5xxx series 9-bit samples */ analog.channels = devc->enabled_channels; analog.num_samples = num_samples; analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; /* TODO: Check malloc return value. */ analog.data = g_try_malloc(analog.num_samples * sizeof(float) * num_channels); data_offset = 0; for (i = 0; i < analog.num_samples; i++) { /* * The device always sends data for both channels. If a channel * is disabled, it contains a copy of the enabled channel's * data. However, we only send the requested channels to * the bus. * * Voltage values are encoded as a value 0-255 (0-512 on the * DSO-5200*), where the value is a point in the range * represented by the vdiv setting. There are 8 vertical divs, * so e.g. 500mV/div represents 4V peak-to-peak where 0 = -2V * and 255 = +2V. */ /* TODO: Support for DSO-5xxx series 9-bit samples. */ if (devc->ch1_enabled) { range = ((float)vdivs[devc->voltage_ch1][0] / vdivs[devc->voltage_ch1][1]) * 8; ch1 = range / 255 * *(buf + i * 2 + 1); /* Value is centered around 0V. */ ch1 -= range / 2; analog.data[data_offset++] = ch1; } if (devc->ch2_enabled) { range = ((float)vdivs[devc->voltage_ch2][0] / vdivs[devc->voltage_ch2][1]) * 8; ch2 = range / 255 * *(buf + i * 2); ch2 -= range / 2; analog.data[data_offset++] = ch2; } } sr_session_send(devc->cb_data, &packet); } /* * Called by libusb (as triggered by handle_event()) when a transfer comes in. * Only channel data comes in asynchronously, and all transfers for this are * queued up beforehand, so this just needs to chuck the incoming data onto * the libsigrok session bus. */ static void receive_transfer(struct libusb_transfer *transfer) { struct sr_datafeed_packet packet; struct sr_dev_inst *sdi; struct dev_context *devc; int num_samples, pre; sdi = transfer->user_data; devc = sdi->priv; sr_spew("receive_transfer(): status %d received %d bytes.", transfer->status, transfer->actual_length); if (transfer->actual_length == 0) /* Nothing to send to the bus. */ return; num_samples = transfer->actual_length / 2; sr_spew("Got %d-%d/%d samples in frame.", devc->samp_received + 1, devc->samp_received + num_samples, devc->framesize); /* * The device always sends a full frame, but the beginning of the frame * doesn't represent the trigger point. The offset at which the trigger * happened came in with the capture state, so we need to start sending * from there up the session bus. The samples in the frame buffer * before that trigger point came after the end of the device's frame * buffer was reached, and it wrapped around to overwrite up until the * trigger point. */ if (devc->samp_received < devc->trigger_offset) { /* Trigger point not yet reached. */ if (devc->samp_received + num_samples < devc->trigger_offset) { /* The entire chunk is before the trigger point. */ memcpy(devc->framebuf + devc->samp_buffered * 2, transfer->buffer, num_samples * 2); devc->samp_buffered += num_samples; } else { /* * This chunk hits or overruns the trigger point. * Store the part before the trigger fired, and * send the rest up to the session bus. */ pre = devc->trigger_offset - devc->samp_received; memcpy(devc->framebuf + devc->samp_buffered * 2, transfer->buffer, pre * 2); devc->samp_buffered += pre; /* The rest of this chunk starts with the trigger point. */ sr_dbg("Reached trigger point, %d samples buffered.", devc->samp_buffered); /* Avoid the corner case where the chunk ended at * exactly the trigger point. */ if (num_samples > pre) send_chunk(sdi, transfer->buffer + pre * 2, num_samples - pre); } } else { /* Already past the trigger point, just send it all out. */ send_chunk(sdi, transfer->buffer, num_samples); } devc->samp_received += num_samples; /* Everything in this transfer was either copied to the buffer or * sent to the session bus. */ g_free(transfer->buffer); libusb_free_transfer(transfer); if (devc->samp_received >= devc->framesize) { /* That was the last chunk in this frame. Send the buffered * pre-trigger samples out now, in one big chunk. */ sr_dbg("End of frame, sending %d pre-trigger buffered samples.", devc->samp_buffered); send_chunk(sdi, devc->framebuf, devc->samp_buffered); /* Mark the end of this frame. */ packet.type = SR_DF_FRAME_END; sr_session_send(devc->cb_data, &packet); if (devc->limit_frames && ++devc->num_frames == devc->limit_frames) { /* Terminate session */ devc->dev_state = STOPPING; } else { devc->dev_state = NEW_CAPTURE; } } } static int handle_event(int fd, int revents, void *cb_data) { const struct sr_dev_inst *sdi; struct sr_datafeed_packet packet; struct timeval tv; struct dev_context *devc; struct drv_context *drvc = di->priv; int num_channels; uint32_t trigger_offset; uint8_t capturestate; (void)fd; (void)revents; sdi = cb_data; devc = sdi->priv; if (devc->dev_state == STOPPING) { /* We've been told to wind up the acquisition. */ sr_dbg("Stopping acquisition."); /* * TODO: Doesn't really cancel pending transfers so they might * come in after SR_DF_END is sent. */ usb_source_remove(drvc->sr_ctx); packet.type = SR_DF_END; sr_session_send(sdi, &packet); devc->dev_state = IDLE; return TRUE; } /* Always handle pending libusb events. */ tv.tv_sec = tv.tv_usec = 0; libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv); /* TODO: ugh */ if (devc->dev_state == NEW_CAPTURE) { if (dso_capture_start(sdi) != SR_OK) return TRUE; if (dso_enable_trigger(sdi) != SR_OK) return TRUE; // if (dso_force_trigger(sdi) != SR_OK) // return TRUE; sr_dbg("Successfully requested next chunk."); devc->dev_state = CAPTURE; return TRUE; } if (devc->dev_state != CAPTURE) return TRUE; if ((dso_get_capturestate(sdi, &capturestate, &trigger_offset)) != SR_OK) return TRUE; sr_dbg("Capturestate %d.", capturestate); sr_dbg("Trigger offset 0x%.6x.", trigger_offset); switch (capturestate) { case CAPTURE_EMPTY: if (++devc->capture_empty_count >= MAX_CAPTURE_EMPTY) { devc->capture_empty_count = 0; if (dso_capture_start(sdi) != SR_OK) break; if (dso_enable_trigger(sdi) != SR_OK) break; // if (dso_force_trigger(sdi) != SR_OK) // break; sr_dbg("Successfully requested next chunk."); } break; case CAPTURE_FILLING: /* No data yet. */ break; case CAPTURE_READY_8BIT: /* Remember where in the captured frame the trigger is. */ devc->trigger_offset = trigger_offset; num_channels = (devc->ch1_enabled && devc->ch2_enabled) ? 2 : 1; /* TODO: Check malloc return value. */ devc->framebuf = g_try_malloc(devc->framesize * num_channels * 2); devc->samp_buffered = devc->samp_received = 0; /* Tell the scope to send us the first frame. */ if (dso_get_channeldata(sdi, receive_transfer) != SR_OK) break; /* * Don't hit the state machine again until we're done fetching * the data we just told the scope to send. */ devc->dev_state = FETCH_DATA; /* Tell the frontend a new frame is on the way. */ packet.type = SR_DF_FRAME_BEGIN; sr_session_send(sdi, &packet); break; case CAPTURE_READY_9BIT: /* TODO */ sr_err("Not yet supported."); break; case CAPTURE_TIMEOUT: /* Doesn't matter, we'll try again next time. */ break; default: sr_dbg("Unknown capture state: %d.", capturestate); break; } return TRUE; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct drv_context *drvc = di->priv; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; devc->cb_data = cb_data; if (configure_channels(sdi) != SR_OK) { sr_err("Failed to configure channels."); return SR_ERR; } if (dso_init(sdi) != SR_OK) return SR_ERR; if (dso_capture_start(sdi) != SR_OK) return SR_ERR; devc->dev_state = CAPTURE; usb_source_add(drvc->sr_ctx, TICK, handle_event, (void *)sdi); /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; (void)cb_data; if (sdi->status != SR_ST_ACTIVE) return SR_ERR; devc = sdi->priv; devc->dev_state = STOPPING; return SR_OK; } SR_PRIV struct sr_dev_driver hantek_dso_driver_info = { .name = "hantek-dso", .longname = "Hantek DSO", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = dev_clear, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/hantek-dso/dso.h0000644000175000017500000001176512332246667015235 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * With protocol information from the hantekdso project, * Copyright (C) 2008 Oleg Khudyakov * * 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 . */ #ifndef LIBSIGROK_HARDWARE_HANTEK_DSO_DSO_H #define LIBSIGROK_HARDWARE_HANTEK_DSO_DSO_H #define LOG_PREFIX "hantek-dso" #define USB_INTERFACE 0 #define USB_CONFIGURATION 1 #define DSO_EP_IN 0x86 #define DSO_EP_OUT 0x02 /* FX2 renumeration delay in ms */ #define MAX_RENUM_DELAY_MS 3000 #define MAX_CAPTURE_EMPTY 3 #define DEFAULT_VOLTAGE VDIV_500MV #define DEFAULT_FRAMESIZE FRAMESIZE_SMALL #define DEFAULT_TIMEBASE TIME_100us #define DEFAULT_TRIGGER_SOURCE "CH1" #define DEFAULT_COUPLING COUPLING_DC #define DEFAULT_HORIZ_TRIGGERPOS 0.5 #define DEFAULT_VERT_OFFSET 0.5 #define DEFAULT_VERT_TRIGGERPOS 0.5 #define MAX_VERT_TRIGGER 0xfe /* Hantek DSO-specific protocol values */ #define EEPROM_CHANNEL_OFFSETS 0x08 /* All models have this for their "fast" mode. */ #define FRAMESIZE_SMALL 10240 enum control_requests { CTRL_READ_EEPROM = 0xa2, CTRL_GETSPEED = 0xb2, CTRL_BEGINCOMMAND = 0xb3, CTRL_SETOFFSET = 0xb4, CTRL_SETRELAYS = 0xb5, }; enum dso_commands { CMD_SET_FILTERS = 0, CMD_SET_TRIGGER_SAMPLERATE, CMD_FORCE_TRIGGER, CMD_CAPTURE_START, CMD_ENABLE_TRIGGER, CMD_GET_CHANNELDATA, CMD_GET_CAPTURESTATE, CMD_SET_VOLTAGE, /* unused */ CMD_SET_LOGICALDATA, CMD_GET_LOGICALDATA, }; /* Must match the coupling table. */ enum couplings { COUPLING_AC = 0, COUPLING_DC, /* TODO not used, how to enable? */ COUPLING_GND, }; /* Must match the timebases table. */ enum time_bases { TIME_10us = 0, TIME_20us, TIME_40us, TIME_100us, TIME_200us, TIME_400us, TIME_1ms, TIME_2ms, TIME_4ms, TIME_10ms, TIME_20ms, TIME_40ms, TIME_100ms, TIME_200ms, TIME_400ms, }; /* Must match the vdivs table. */ enum { VDIV_10MV, VDIV_20MV, VDIV_50MV, VDIV_100MV, VDIV_200MV, VDIV_500MV, VDIV_1V, VDIV_2V, VDIV_5V, }; enum trigger_slopes { SLOPE_POSITIVE = 0, SLOPE_NEGATIVE, }; enum trigger_sources { TRIGGER_CH2 = 0, TRIGGER_CH1, TRIGGER_EXT, }; enum capturestates { CAPTURE_EMPTY = 0, CAPTURE_FILLING = 1, CAPTURE_READY_8BIT = 2, CAPTURE_READY_9BIT = 7, CAPTURE_TIMEOUT = 127, CAPTURE_UNKNOWN = 255, }; enum triggermodes { TRIGGERMODE_AUTO, TRIGGERMODE_NORMAL, TRIGGERMODE_SINGLE, }; enum states { IDLE, NEW_CAPTURE, CAPTURE, FETCH_DATA, STOPPING, }; struct dso_profile { /* VID/PID after cold boot */ uint16_t orig_vid; uint16_t orig_pid; /* VID/PID after firmware upload */ uint16_t fw_vid; uint16_t fw_pid; char *vendor; char *model; const uint64_t *buffersizes; char *firmware; }; struct dev_context { const struct dso_profile *profile; void *cb_data; uint64_t limit_frames; uint64_t num_frames; GSList *enabled_channels; /* We can't keep track of an FX2-based device after upgrading * the firmware (it re-enumerates into a different device address * after the upgrade) this is like a global lock. No device will open * until a proper delay after the last device was upgraded. */ int64_t fw_updated; int epin_maxpacketsize; int capture_empty_count; int dev_state; /* Oscilloscope settings. */ int timebase; gboolean ch1_enabled; gboolean ch2_enabled; int voltage_ch1; int voltage_ch2; int coupling_ch1; int coupling_ch2; // voltage offset (vertical position) float voffset_ch1; float voffset_ch2; float voffset_trigger; uint16_t channel_levels[2][9][2]; unsigned int framesize; gboolean filter_ch1; gboolean filter_ch2; gboolean filter_trigger; int triggerslope; char *triggersource; float triggerposition; int triggermode; /* Frame transfer */ unsigned int samp_received; unsigned int samp_buffered; unsigned int trigger_offset; unsigned char *framebuf; }; SR_PRIV int dso_open(struct sr_dev_inst *sdi); SR_PRIV void dso_close(struct sr_dev_inst *sdi); SR_PRIV int dso_enable_trigger(const struct sr_dev_inst *sdi); SR_PRIV int dso_force_trigger(const struct sr_dev_inst *sdi); SR_PRIV int dso_init(const struct sr_dev_inst *sdi); SR_PRIV int dso_get_capturestate(const struct sr_dev_inst *sdi, uint8_t *capturestate, uint32_t *trigger_offset); SR_PRIV int dso_capture_start(const struct sr_dev_inst *sdi); SR_PRIV int dso_get_channeldata(const struct sr_dev_inst *sdi, libusb_transfer_cb_fn cb); #endif libsigrok-0.3.0/hardware/agilent-dmm/0000755000175000017500000000000012332246734014501 500000000000000libsigrok-0.3.0/hardware/agilent-dmm/sched.c0000644000175000017500000002752012332246667015666 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "agilent-dmm.h" #include #include #include #include static void dispatch(const struct sr_dev_inst *sdi) { struct dev_context *devc; const struct agdmm_job *jobs; int64_t now; int i; devc = sdi->priv; jobs = devc->profile->jobs; now = g_get_monotonic_time() / 1000; for (i = 0; (&jobs[i])->interval; i++) { if (now - devc->jobqueue[i] > (&jobs[i])->interval) { sr_spew("Running job %d.", i); (&jobs[i])->send(sdi); devc->jobqueue[i] = now; } } } static void receive_line(const struct sr_dev_inst *sdi) { struct dev_context *devc; const struct agdmm_recv *recvs, *recv; GRegex *reg; GMatchInfo *match; int i; devc = sdi->priv; /* Strip CRLF */ while (devc->buflen) { if (*(devc->buf + devc->buflen - 1) == '\r' || *(devc->buf + devc->buflen - 1) == '\n') *(devc->buf + --devc->buflen) = '\0'; else break; } sr_spew("Received '%s'.", devc->buf); recv = NULL; recvs = devc->profile->recvs; for (i = 0; (&recvs[i])->recv_regex; i++) { reg = g_regex_new((&recvs[i])->recv_regex, 0, 0, NULL); if (g_regex_match(reg, (char *)devc->buf, 0, &match)) { recv = &recvs[i]; break; } g_match_info_unref(match); g_regex_unref(reg); } if (recv) { recv->recv(sdi, match); g_match_info_unref(match); g_regex_unref(reg); } else sr_dbg("Unknown line '%s'.", devc->buf); /* Done with this. */ devc->buflen = 0; } SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_serial_dev_inst *serial; int len; (void)fd; if (!(sdi = cb_data)) return TRUE; if (!(devc = sdi->priv)) return TRUE; serial = sdi->conn; if (revents == G_IO_IN) { /* Serial data arrived. */ while(AGDMM_BUFSIZE - devc->buflen - 1 > 0) { len = serial_read(serial, devc->buf + devc->buflen, 1); if (len < 1) break; devc->buflen += len; *(devc->buf + devc->buflen) = '\0'; if (*(devc->buf + devc->buflen - 1) == '\n') { /* End of line */ receive_line(sdi); break; } } } dispatch(sdi); if (devc->limit_samples && devc->num_samples >= devc->limit_samples) sdi->driver->dev_acquisition_stop(sdi, cb_data); return TRUE; } static int agdmm_send(const struct sr_dev_inst *sdi, const char *cmd) { struct sr_serial_dev_inst *serial; char buf[32]; serial = sdi->conn; sr_spew("Sending '%s'.", cmd); strncpy(buf, cmd, 28); if (!strncmp(buf, "*IDN?", 5)) strncat(buf, "\r\n", 32); else strncat(buf, "\n\r\n", 32); if (serial_write(serial, buf, strlen(buf)) == -1) { sr_err("Failed to send: %s.", strerror(errno)); return SR_ERR; } return SR_OK; } static int send_stat(const struct sr_dev_inst *sdi) { return agdmm_send(sdi, "STAT?"); } static int recv_stat_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match) { struct dev_context *devc; char *s; devc = sdi->priv; s = g_match_info_fetch(match, 1); sr_spew("STAT response '%s'.", s); /* Max, Min or Avg mode -- no way to tell which, so we'll * set both flags to denote it's not a normal measurement. */ if (s[0] == '1') devc->cur_mqflags |= SR_MQFLAG_MAX | SR_MQFLAG_MIN; else devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN); if (s[1] == '1') devc->cur_mqflags |= SR_MQFLAG_RELATIVE; else devc->cur_mqflags &= ~SR_MQFLAG_RELATIVE; /* Triggered or auto hold modes. */ if (s[2] == '1' || s[3] == '1') devc->cur_mqflags |= SR_MQFLAG_HOLD; else devc->cur_mqflags &= ~SR_MQFLAG_HOLD; /* Temp/aux mode. */ if (s[7] == '1') devc->mode_tempaux = TRUE; else devc->mode_tempaux = FALSE; /* Continuity mode. */ if (s[16] == '1') devc->mode_continuity = TRUE; else devc->mode_continuity = FALSE; g_free(s); return SR_OK; } static int recv_stat_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match) { struct dev_context *devc; char *s; devc = sdi->priv; s = g_match_info_fetch(match, 1); sr_spew("STAT response '%s'.", s); /* Peak hold mode. */ if (s[4] == '1') devc->cur_mqflags |= SR_MQFLAG_MAX; else devc->cur_mqflags &= ~SR_MQFLAG_MAX; /* Triggered hold mode. */ if (s[7] == '1') devc->cur_mqflags |= SR_MQFLAG_HOLD; else devc->cur_mqflags &= ~SR_MQFLAG_HOLD; g_free(s); return SR_OK; } static int send_fetc(const struct sr_dev_inst *sdi) { return agdmm_send(sdi, "FETC?"); } static int recv_fetc(const struct sr_dev_inst *sdi, GMatchInfo *match) { struct dev_context *devc; struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; float fvalue; char *mstr; sr_spew("FETC reply '%s'.", g_match_info_get_string(match)); devc = sdi->priv; if (devc->cur_mq == -1) /* Haven't seen configuration yet, so can't know what * the fetched float means. Not really an error, we'll * get metadata soon enough. */ return SR_OK; if (!strcmp(g_match_info_get_string(match), "+9.90000000E+37")) { /* An invalid measurement shows up on the display as "O.L", but * comes through like this. Since comparing 38-digit floats * is rather problematic, we'll cut through this here. */ fvalue = NAN; } else { mstr = g_match_info_fetch(match, 1); if (sr_atof_ascii(mstr, &fvalue) != SR_OK || fvalue == 0.0) { g_free(mstr); sr_err("Invalid float."); return SR_ERR; } g_free(mstr); if (devc->cur_divider > 0) fvalue /= devc->cur_divider; } memset(&analog, 0, sizeof(struct sr_datafeed_analog)); analog.mq = devc->cur_mq; analog.unit = devc->cur_unit; analog.mqflags = devc->cur_mqflags; analog.channels = sdi->channels; analog.num_samples = 1; analog.data = &fvalue; packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(devc->cb_data, &packet); devc->num_samples++; return SR_OK; } static int send_conf(const struct sr_dev_inst *sdi) { return agdmm_send(sdi, "CONF?"); } static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match) { struct dev_context *devc; char *mstr; sr_spew("CONF? response '%s'.", g_match_info_get_string(match)); devc = sdi->priv; mstr = g_match_info_fetch(match, 1); if (!strcmp(mstr, "V")) { devc->cur_mq = SR_MQ_VOLTAGE; devc->cur_unit = SR_UNIT_VOLT; devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "MV")) { if (devc->mode_tempaux) { devc->cur_mq = SR_MQ_TEMPERATURE; /* No way to detect whether Fahrenheit or Celcius * is used, so we'll just default to Celcius. */ devc->cur_unit = SR_UNIT_CELSIUS; devc->cur_mqflags = 0; devc->cur_divider = 0; } else { devc->cur_mq = SR_MQ_VOLTAGE; devc->cur_unit = SR_UNIT_VOLT; devc->cur_mqflags = 0; devc->cur_divider = 1000; } } else if(!strcmp(mstr, "A")) { devc->cur_mq = SR_MQ_CURRENT; devc->cur_unit = SR_UNIT_AMPERE; devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "UA")) { devc->cur_mq = SR_MQ_CURRENT; devc->cur_unit = SR_UNIT_AMPERE; devc->cur_mqflags = 0; devc->cur_divider = 1000000; } else if(!strcmp(mstr, "FREQ")) { devc->cur_mq = SR_MQ_FREQUENCY; devc->cur_unit = SR_UNIT_HERTZ; devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "RES")) { if (devc->mode_continuity) { devc->cur_mq = SR_MQ_CONTINUITY; devc->cur_unit = SR_UNIT_BOOLEAN; } else { devc->cur_mq = SR_MQ_RESISTANCE; devc->cur_unit = SR_UNIT_OHM; } devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "CAP")) { devc->cur_mq = SR_MQ_CAPACITANCE; devc->cur_unit = SR_UNIT_FARAD; devc->cur_mqflags = 0; devc->cur_divider = 0; } else sr_dbg("Unknown first argument."); g_free(mstr); if (g_match_info_get_match_count(match) == 4) { mstr = g_match_info_fetch(match, 3); /* Third value, if present, is always AC or DC. */ if (!strcmp(mstr, "AC")) devc->cur_mqflags |= SR_MQFLAG_AC; else if (!strcmp(mstr, "DC")) devc->cur_mqflags |= SR_MQFLAG_DC; else sr_dbg("Unknown third argument."); g_free(mstr); } else devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC); return SR_OK; } static int recv_conf_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match) { struct dev_context *devc; char *mstr; sr_spew("CONF? response '%s'.", g_match_info_get_string(match)); devc = sdi->priv; mstr = g_match_info_fetch(match, 1); if (!strncmp(mstr, "VOLT", 4)) { devc->cur_mq = SR_MQ_VOLTAGE; devc->cur_unit = SR_UNIT_VOLT; devc->cur_mqflags = 0; devc->cur_divider = 0; if (mstr[4] == ':') { if (!strcmp(mstr + 4, "AC")) devc->cur_mqflags |= SR_MQFLAG_AC; else if (!strcmp(mstr + 4, "DC")) devc->cur_mqflags |= SR_MQFLAG_DC; else /* "ACDC" appears as well, no idea what it means. */ devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC); } else devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC); } else if(!strcmp(mstr, "CURR")) { devc->cur_mq = SR_MQ_CURRENT; devc->cur_unit = SR_UNIT_AMPERE; devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "RES")) { if (devc->mode_continuity) { devc->cur_mq = SR_MQ_CONTINUITY; devc->cur_unit = SR_UNIT_BOOLEAN; } else { devc->cur_mq = SR_MQ_RESISTANCE; devc->cur_unit = SR_UNIT_OHM; } devc->cur_mqflags = 0; devc->cur_divider = 0; } else sr_dbg("Unknown first argument."); g_free(mstr); return SR_OK; } /* At least the 123x and 125x appear to have this. */ static int recv_conf(const struct sr_dev_inst *sdi, GMatchInfo *match) { struct dev_context *devc; char *mstr; sr_spew("CONF? response '%s'.", g_match_info_get_string(match)); devc = sdi->priv; mstr = g_match_info_fetch(match, 1); if(!strcmp(mstr, "DIOD")) { devc->cur_mq = SR_MQ_VOLTAGE; devc->cur_unit = SR_UNIT_VOLT; devc->cur_mqflags = SR_MQFLAG_DIODE; devc->cur_divider = 0; } else sr_dbg("Unknown single argument."); g_free(mstr); return SR_OK; } /* This comes in whenever the rotary switch is changed to a new position. * We could use it to determine the major measurement mode, but we already * have the output of CONF? for that, which is more detailed. However * we do need to catch this here, or it'll show up in some other output. */ static int recv_switch(const struct sr_dev_inst *sdi, GMatchInfo *match) { (void)sdi; sr_spew("Switch '%s'.", g_match_info_get_string(match)); return SR_OK; } SR_PRIV const struct agdmm_job agdmm_jobs_u123x[] = { { 143, send_stat }, { 1000, send_conf }, { 143, send_fetc }, { 0, NULL } }; SR_PRIV const struct agdmm_recv agdmm_recvs_u123x[] = { { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u123x }, { "^\\*([0-9])$", recv_switch }, { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc }, { "^\"(V|MV|A|UA|FREQ),(\\d),(AC|DC)\"$", recv_conf_u123x }, { "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x}, { "^\"(DIOD)\"$", recv_conf }, { NULL, NULL } }; SR_PRIV const struct agdmm_job agdmm_jobs_u125x[] = { { 143, send_stat }, { 1000, send_conf }, { 143, send_fetc }, { 0, NULL } }; SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = { { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x }, { "^\\*([0-9])$", recv_switch }, { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc }, { "^(VOLT|CURR|RES|CAP) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x }, { "^(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x }, { "^\"(DIOD)\"$", recv_conf }, { NULL, NULL } }; libsigrok-0.3.0/hardware/agilent-dmm/agilent-dmm.h0000644000175000017500000000364712332246667017007 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #ifndef LIBSIGROK_HARDWARE_AGILENT_DMM_AGILENT_DMM_H #define LIBSIGROK_HARDWARE_AGILENT_DMM_AGILENT_DMM_H #define LOG_PREFIX "agilent-dmm" #define AGDMM_BUFSIZE 256 /* Supported models */ enum { AGILENT_U1231A = 1, AGILENT_U1232A, AGILENT_U1233A, AGILENT_U1251A, AGILENT_U1252A, AGILENT_U1253A, }; /* Supported device profiles */ struct agdmm_profile { int model; const char *modelname; const struct agdmm_job *jobs; const struct agdmm_recv *recvs; }; /* Private, per-device-instance driver context. */ struct dev_context { const struct agdmm_profile *profile; uint64_t limit_samples; uint64_t limit_msec; /* Opaque pointer passed in by the frontend. */ void *cb_data; /* Runtime. */ uint64_t num_samples; int64_t jobqueue[8]; unsigned char buf[AGDMM_BUFSIZE]; int buflen; int cur_mq; int cur_unit; int cur_mqflags; int cur_divider; int cur_acdc; int mode_tempaux; int mode_continuity; }; struct agdmm_job { int interval; int (*send) (const struct sr_dev_inst *sdi); }; struct agdmm_recv { const char *recv_regex; int (*recv) (const struct sr_dev_inst *sdi, GMatchInfo *match); }; SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data); #endif libsigrok-0.3.0/hardware/agilent-dmm/api.c0000644000175000017500000001603312332246667015346 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * * 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 . */ #include #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "agilent-dmm.h" static const int32_t hwopts[] = { SR_CONF_CONN, SR_CONF_SERIALCOMM, }; static const int32_t hwcaps[] = { SR_CONF_MULTIMETER, SR_CONF_LIMIT_SAMPLES, SR_CONF_LIMIT_MSEC, SR_CONF_CONTINUOUS, }; extern const struct agdmm_job agdmm_jobs_u123x[]; extern const struct agdmm_recv agdmm_recvs_u123x[]; extern const struct agdmm_job agdmm_jobs_u125x[]; extern const struct agdmm_recv agdmm_recvs_u125x[]; /* This works on all the Agilent U12xxA series, although the * U127xA can apparently also run at 19200/8n1. */ #define SERIALCOMM "9600/8n1" static const struct agdmm_profile supported_agdmm[] = { { AGILENT_U1231A, "U1231A", agdmm_jobs_u123x, agdmm_recvs_u123x }, { AGILENT_U1232A, "U1232A", agdmm_jobs_u123x, agdmm_recvs_u123x }, { AGILENT_U1233A, "U1233A", agdmm_jobs_u123x, agdmm_recvs_u123x }, { AGILENT_U1251A, "U1251A", agdmm_jobs_u125x, agdmm_recvs_u125x }, { AGILENT_U1252A, "U1252A", agdmm_jobs_u125x, agdmm_recvs_u125x }, { AGILENT_U1253A, "U1253A", agdmm_jobs_u125x, agdmm_recvs_u125x }, { 0, NULL, NULL, NULL } }; SR_PRIV struct sr_dev_driver agdmm_driver_info; static struct sr_dev_driver *di = &agdmm_driver_info; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct sr_dev_inst *sdi; struct drv_context *drvc; struct dev_context *devc; struct sr_config *src; struct sr_channel *ch; struct sr_serial_dev_inst *serial; GSList *l, *devices; int len, i; const char *conn, *serialcomm; char *buf, **tokens; drvc = di->priv; drvc->instances = NULL; devices = NULL; conn = serialcomm = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; case SR_CONF_SERIALCOMM: serialcomm = g_variant_get_string(src->data, NULL); break; } } if (!conn) return NULL; if (!serialcomm) serialcomm = SERIALCOMM; if (!(serial = sr_serial_dev_inst_new(conn, serialcomm))) return NULL; if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return NULL; serial_flush(serial); if (serial_write(serial, "*IDN?\r\n", 7) == -1) { sr_err("Unable to send identification string: %s.", strerror(errno)); return NULL; } len = 128; if (!(buf = g_try_malloc(len))) { sr_err("Serial buffer malloc failed."); return NULL; } serial_readline(serial, &buf, &len, 150); if (!len) return NULL; tokens = g_strsplit(buf, ",", 4); if (!strcmp("Agilent Technologies", tokens[0]) && tokens[1] && tokens[2] && tokens[3]) { for (i = 0; supported_agdmm[i].model; i++) { if (strcmp(supported_agdmm[i].modelname, tokens[1])) continue; if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Agilent", tokens[1], tokens[3]))) return NULL; if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } devc->profile = &supported_agdmm[i]; devc->cur_mq = -1; sdi->inst_type = SR_INST_SERIAL; sdi->conn = serial; sdi->priv = devc; sdi->driver = di; if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1"))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); break; } } g_strfreev(tokens); g_free(buf); serial_close(serial); if (!devices) sr_serial_dev_inst_free(serial); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int cleanup(void) { return std_dev_clear(di, NULL); } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return SR_ERR_BUG; } switch (id) { case SR_CONF_LIMIT_MSEC: /* TODO: not yet implemented */ if (g_variant_get_uint64(data) == 0) { sr_err("LIMIT_MSEC can't be 0."); return SR_ERR; } devc->limit_msec = g_variant_get_uint64(data); sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec); break; case SR_CONF_LIMIT_SAMPLES: devc->limit_samples = g_variant_get_uint64(data); sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples); break; default: return SR_ERR_NA; } return SR_OK; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { (void)sdi; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; default: return SR_ERR_NA; } return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct sr_serial_dev_inst *serial; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; if (!(devc = sdi->priv)) { sr_err("sdi->priv was NULL."); return SR_ERR_BUG; } devc->cb_data = cb_data; /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); /* Poll every 100ms, or whenever some data comes in. */ serial = sdi->conn; serial_source_add(serial, G_IO_IN, 100, agdmm_receive_data, (void *)sdi); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close, sdi->conn, LOG_PREFIX); } SR_PRIV struct sr_dev_driver agdmm_driver_info = { .name = "agilent-dmm", .longname = "Agilent U12xx series DMMs", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = NULL, .config_set = config_set, .config_list = config_list, .dev_open = std_serial_dev_open, .dev_close = std_serial_dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/openbench-logic-sniffer/0000755000175000017500000000000012332246734016771 500000000000000libsigrok-0.3.0/hardware/openbench-logic-sniffer/protocol.h0000644000175000017500000000743112332246667020735 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen * * 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 . */ #ifndef LIBSIGROK_HARDWARE_OPENBENCH_LOGIC_SNIFFER_PROTOCOL_H #define LIBSIGROK_HARDWARE_OPENBENCH_LOGIC_SNIFFER_PROTOCOL_H #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "ols" #define NUM_CHANNELS 32 #define NUM_TRIGGER_STAGES 4 #define TRIGGER_TYPE "01" #define SERIAL_SPEED B115200 #define CLOCK_RATE SR_MHZ(100) #define MIN_NUM_SAMPLES 4 #define DEFAULT_SAMPLERATE SR_KHZ(200) /* Command opcodes */ #define CMD_RESET 0x00 #define CMD_RUN 0x01 #define CMD_TESTMODE 0x03 #define CMD_ID 0x02 #define CMD_METADATA 0x04 #define CMD_SET_FLAGS 0x82 #define CMD_SET_DIVIDER 0x80 #define CMD_CAPTURE_SIZE 0x81 #define CMD_SET_TRIGGER_MASK 0xc0 #define CMD_SET_TRIGGER_VALUE 0xc1 #define CMD_SET_TRIGGER_CONFIG 0xc2 /* Trigger config */ #define TRIGGER_START (1 << 3) /* Bitmasks for CMD_FLAGS */ /* 12-13 unused, 14-15 RLE mode (we hardcode mode 0). */ #define FLAG_INTERNAL_TEST_MODE (1 << 11) #define FLAG_EXTERNAL_TEST_MODE (1 << 10) #define FLAG_SWAP_CHANNELS (1 << 9) #define FLAG_RLE (1 << 8) #define FLAG_SLOPE_FALLING (1 << 7) #define FLAG_CLOCK_EXTERNAL (1 << 6) #define FLAG_CHANNELGROUP_4 (1 << 5) #define FLAG_CHANNELGROUP_3 (1 << 4) #define FLAG_CHANNELGROUP_2 (1 << 3) #define FLAG_CHANNELGROUP_1 (1 << 2) #define FLAG_FILTER (1 << 1) #define FLAG_DEMUX (1 << 0) /* Private, per-device-instance driver context. */ struct dev_context { /* Fixed device settings */ int max_channels; uint32_t max_samples; uint32_t max_samplerate; uint32_t protocol_version; /* Acquisition settings */ uint64_t cur_samplerate; uint32_t cur_samplerate_divider; uint64_t limit_samples; int capture_ratio; int trigger_at; uint32_t channel_mask; uint32_t trigger_mask[4]; uint32_t trigger_value[4]; int num_stages; uint16_t flag_reg; /* Operational states */ unsigned int num_transfers; unsigned int num_samples; int num_bytes; int cnt_bytes; int cnt_samples; int cnt_samples_rle; /* Temporary variables */ unsigned int rle_count; unsigned char sample[4]; unsigned char tmp_sample[4]; unsigned char *raw_sample_buf; }; SR_PRIV extern const char *ols_channel_names[NUM_CHANNELS + 1]; SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, uint8_t command); SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial, uint8_t command, uint8_t *data); SR_PRIV int ols_configure_channels(const struct sr_dev_inst *sdi); SR_PRIV struct dev_context *ols_dev_new(void); SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial); SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate); SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi); SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data); #endif libsigrok-0.3.0/hardware/openbench-logic-sniffer/protocol.c0000644000175000017500000003266412332246667020736 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen * * 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 . */ #include "protocol.h" #include extern SR_PRIV struct sr_dev_driver ols_driver_info; static struct sr_dev_driver *di = &ols_driver_info; SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, uint8_t command) { char buf[1]; sr_dbg("Sending cmd 0x%.2x.", command); buf[0] = command; if (serial_write_blocking(serial, buf, 1) != 1) return SR_ERR; return SR_OK; } SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial, uint8_t command, uint8_t *data) { char buf[5]; sr_dbg("Sending cmd 0x%.2x data 0x%.2x%.2x%.2x%.2x.", command, data[0], data[1], data[2], data[3]); buf[0] = command; buf[1] = data[0]; buf[2] = data[1]; buf[3] = data[2]; buf[4] = data[3]; if (serial_write_blocking(serial, buf, 5) != 5) return SR_ERR; return SR_OK; } SR_PRIV int ols_configure_channels(const struct sr_dev_inst *sdi) { struct dev_context *devc; const struct sr_channel *ch; const GSList *l; int channel_bit, stage, i; char *tc; devc = sdi->priv; devc->channel_mask = 0; for (i = 0; i < NUM_TRIGGER_STAGES; i++) { devc->trigger_mask[i] = 0; devc->trigger_value[i] = 0; } devc->num_stages = 0; for (l = sdi->channels; l; l = l->next) { ch = (const struct sr_channel *)l->data; if (!ch->enabled) continue; if (ch->index >= devc->max_channels) { sr_err("Channels over the limit of %d\n", devc->max_channels); return SR_ERR; } /* * Set up the channel mask for later configuration into the * flag register. */ channel_bit = 1 << (ch->index); devc->channel_mask |= channel_bit; if (!ch->trigger) continue; /* Configure trigger mask and value. */ stage = 0; for (tc = ch->trigger; tc && *tc; tc++) { devc->trigger_mask[stage] |= channel_bit; if (*tc == '1') devc->trigger_value[stage] |= channel_bit; stage++; /* Only supporting parallel mode, with up to 4 stages. */ if (stage > 4) return SR_ERR; } if (stage > devc->num_stages) devc->num_stages = stage - 1; } return SR_OK; } SR_PRIV struct dev_context *ols_dev_new(void) { struct dev_context *devc; if (!(devc = g_try_malloc(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } /* Device-specific settings */ devc->max_samples = devc->max_samplerate = devc->protocol_version = 0; /* Acquisition settings */ devc->limit_samples = devc->capture_ratio = 0; devc->trigger_at = -1; devc->channel_mask = 0xffffffff; devc->flag_reg = 0; return devc; } SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial) { struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_channel *ch; uint32_t tmp_int, ui; uint8_t key, type, token; GString *tmp_str, *devname, *version; guchar tmp_c; sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, NULL, NULL, NULL); sdi->driver = di; devc = ols_dev_new(); sdi->priv = devc; devname = g_string_new(""); version = g_string_new(""); key = 0xff; while (key) { if (serial_read_blocking(serial, &key, 1) != 1) break; if (key == 0x00) { sr_dbg("Got metadata key 0x00, metadata ends."); break; } type = key >> 5; token = key & 0x1f; switch (type) { case 0: /* NULL-terminated string */ tmp_str = g_string_new(""); while (serial_read_blocking(serial, &tmp_c, 1) == 1 && tmp_c != '\0') g_string_append_c(tmp_str, tmp_c); sr_dbg("Got metadata key 0x%.2x value '%s'.", key, tmp_str->str); switch (token) { case 0x01: /* Device name */ devname = g_string_append(devname, tmp_str->str); break; case 0x02: /* FPGA firmware version */ if (version->len) g_string_append(version, ", "); g_string_append(version, "FPGA version "); g_string_append(version, tmp_str->str); break; case 0x03: /* Ancillary version */ if (version->len) g_string_append(version, ", "); g_string_append(version, "Ancillary version "); g_string_append(version, tmp_str->str); break; default: sr_info("ols: unknown token 0x%.2x: '%s'", token, tmp_str->str); break; } g_string_free(tmp_str, TRUE); break; case 1: /* 32-bit unsigned integer */ if (serial_read_blocking(serial, &tmp_int, 4) != 4) break; tmp_int = RB32(&tmp_int); sr_dbg("Got metadata key 0x%.2x value 0x%.8x.", key, tmp_int); switch (token) { case 0x00: /* Number of usable channels */ for (ui = 0; ui < tmp_int; ui++) { if (!(ch = sr_channel_new(ui, SR_CHANNEL_LOGIC, TRUE, ols_channel_names[ui]))) return 0; sdi->channels = g_slist_append(sdi->channels, ch); } break; case 0x01: /* Amount of sample memory available (bytes) */ devc->max_samples = tmp_int; break; case 0x02: /* Amount of dynamic memory available (bytes) */ /* what is this for? */ break; case 0x03: /* Maximum sample rate (hz) */ devc->max_samplerate = tmp_int; break; case 0x04: /* protocol version */ devc->protocol_version = tmp_int; break; default: sr_info("Unknown token 0x%.2x: 0x%.8x.", token, tmp_int); break; } break; case 2: /* 8-bit unsigned integer */ if (serial_read_blocking(serial, &tmp_c, 1) != 1) break; sr_dbg("Got metadata key 0x%.2x value 0x%.2x.", key, tmp_c); switch (token) { case 0x00: /* Number of usable channels */ for (ui = 0; ui < tmp_c; ui++) { if (!(ch = sr_channel_new(ui, SR_CHANNEL_LOGIC, TRUE, ols_channel_names[ui]))) return 0; sdi->channels = g_slist_append(sdi->channels, ch); } break; case 0x01: /* protocol version */ devc->protocol_version = tmp_c; break; default: sr_info("Unknown token 0x%.2x: 0x%.2x.", token, tmp_c); break; } break; default: /* unknown type */ break; } } sdi->model = devname->str; sdi->version = version->str; g_string_free(devname, FALSE); g_string_free(version, FALSE); return sdi; } SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, const uint64_t samplerate) { struct dev_context *devc; devc = sdi->priv; if (devc->max_samplerate && samplerate > devc->max_samplerate) return SR_ERR_SAMPLERATE; if (samplerate > CLOCK_RATE) { sr_info("Enabling demux mode."); devc->flag_reg |= FLAG_DEMUX; devc->flag_reg &= ~FLAG_FILTER; devc->max_channels = NUM_CHANNELS / 2; devc->cur_samplerate_divider = (CLOCK_RATE * 2 / samplerate) - 1; } else { sr_info("Disabling demux mode."); devc->flag_reg &= ~FLAG_DEMUX; devc->flag_reg |= FLAG_FILTER; devc->max_channels = NUM_CHANNELS; devc->cur_samplerate_divider = (CLOCK_RATE / samplerate) - 1; } /* Calculate actual samplerate used and complain if it is different * from the requested. */ devc->cur_samplerate = CLOCK_RATE / (devc->cur_samplerate_divider + 1); if (devc->flag_reg & FLAG_DEMUX) devc->cur_samplerate *= 2; if (devc->cur_samplerate != samplerate) sr_info("Can't match samplerate %" PRIu64 ", using %" PRIu64 ".", samplerate, devc->cur_samplerate); return SR_OK; } SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi) { struct sr_datafeed_packet packet; struct sr_serial_dev_inst *serial; serial = sdi->conn; serial_source_remove(serial); /* Terminate session */ packet.type = SR_DF_END; sr_session_send(sdi, &packet); } SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) { struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_serial_dev_inst *serial; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; uint32_t sample; int num_channels, offset, j; unsigned int i; unsigned char byte; (void)fd; sdi = cb_data; serial = sdi->conn; devc = sdi->priv; if (devc->num_transfers++ == 0) { /* * First time round, means the device started sending data, * and will not stop until done. If it stops sending for * longer than it takes to send a byte, that means it's * finished. We'll double that to 30ms to be sure... */ serial_source_remove(serial); serial_source_add(serial, G_IO_IN, 30, ols_receive_data, cb_data); devc->raw_sample_buf = g_try_malloc(devc->limit_samples * 4); if (!devc->raw_sample_buf) { sr_err("Sample buffer malloc failed."); return FALSE; } /* fill with 1010... for debugging */ memset(devc->raw_sample_buf, 0x82, devc->limit_samples * 4); } num_channels = 0; for (i = NUM_CHANNELS; i > 0x02; i /= 2) { if ((devc->flag_reg & i) == 0) { num_channels++; } } if (revents == G_IO_IN && devc->num_samples < devc->limit_samples) { if (serial_read_nonblocking(serial, &byte, 1) != 1) return FALSE; devc->cnt_bytes++; /* Ignore it if we've read enough. */ if (devc->num_samples >= devc->limit_samples) return TRUE; devc->sample[devc->num_bytes++] = byte; sr_spew("Received byte 0x%.2x.", byte); if (devc->num_bytes == num_channels) { devc->cnt_samples++; devc->cnt_samples_rle++; /* * Got a full sample. Convert from the OLS's little-endian * sample to the local format. */ sample = devc->sample[0] | (devc->sample[1] << 8) \ | (devc->sample[2] << 16) | (devc->sample[3] << 24); sr_dbg("Received sample 0x%.*x.", devc->num_bytes * 2, sample); if (devc->flag_reg & FLAG_RLE) { /* * In RLE mode the high bit of the sample is the * "count" flag, meaning this sample is the number * of times the previous sample occurred. */ if (devc->sample[devc->num_bytes - 1] & 0x80) { /* Clear the high bit. */ sample &= ~(0x80 << (devc->num_bytes - 1) * 8); devc->rle_count = sample; devc->cnt_samples_rle += devc->rle_count; sr_dbg("RLE count: %u.", devc->rle_count); devc->num_bytes = 0; return TRUE; } } devc->num_samples += devc->rle_count + 1; if (devc->num_samples > devc->limit_samples) { /* Save us from overrunning the buffer. */ devc->rle_count -= devc->num_samples - devc->limit_samples; devc->num_samples = devc->limit_samples; } if (num_channels < 4) { /* * Some channel groups may have been turned * off, to speed up transfer between the * hardware and the PC. Expand that here before * submitting it over the session bus -- * whatever is listening on the bus will be * expecting a full 32-bit sample, based on * the number of channels. */ j = 0; memset(devc->tmp_sample, 0, 4); for (i = 0; i < 4; i++) { if (((devc->flag_reg >> 2) & (1 << i)) == 0) { /* * This channel group was * enabled, copy from received * sample. */ devc->tmp_sample[i] = devc->sample[j++]; } else if (devc->flag_reg & FLAG_DEMUX && (i > 2)) { /* group 2 & 3 get added to 0 & 1 */ devc->tmp_sample[i - 2] = devc->sample[j++]; } } memcpy(devc->sample, devc->tmp_sample, 4); sr_spew("Expanded sample: 0x%.8x.", sample); } /* * the OLS sends its sample buffer backwards. * store it in reverse order here, so we can dump * this on the session bus later. */ offset = (devc->limit_samples - devc->num_samples) * 4; for (i = 0; i <= devc->rle_count; i++) { memcpy(devc->raw_sample_buf + offset + (i * 4), devc->sample, 4); } memset(devc->sample, 0, 4); devc->num_bytes = 0; devc->rle_count = 0; } } else { /* * This is the main loop telling us a timeout was reached, or * we've acquired all the samples we asked for -- we're done. * Send the (properly-ordered) buffer to the frontend. */ sr_dbg("Received %d bytes, %d samples, %d decompressed samples.", devc->cnt_bytes, devc->cnt_samples, devc->cnt_samples_rle); if (devc->trigger_at != -1) { /* * A trigger was set up, so we need to tell the frontend * about it. */ if (devc->trigger_at > 0) { /* There are pre-trigger samples, send those first. */ packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = devc->trigger_at * 4; logic.unitsize = 4; logic.data = devc->raw_sample_buf + (devc->limit_samples - devc->num_samples) * 4; sr_session_send(cb_data, &packet); } /* Send the trigger. */ packet.type = SR_DF_TRIGGER; sr_session_send(cb_data, &packet); /* Send post-trigger samples. */ packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = (devc->num_samples * 4) - (devc->trigger_at * 4); logic.unitsize = 4; logic.data = devc->raw_sample_buf + devc->trigger_at * 4 + (devc->limit_samples - devc->num_samples) * 4; sr_session_send(cb_data, &packet); } else { /* no trigger was used */ packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = devc->num_samples * 4; logic.unitsize = 4; logic.data = devc->raw_sample_buf + (devc->limit_samples - devc->num_samples) * 4; sr_session_send(cb_data, &packet); } g_free(devc->raw_sample_buf); serial_flush(serial); abort_acquisition(sdi); } return TRUE; } libsigrok-0.3.0/hardware/openbench-logic-sniffer/api.c0000644000175000017500000003736012332246667017644 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen * * 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 . */ #include "protocol.h" #include #define SERIALCOMM "115200/8n1" static const int32_t hwopts[] = { SR_CONF_CONN, SR_CONF_SERIALCOMM, }; static const int32_t hwcaps[] = { SR_CONF_LOGIC_ANALYZER, SR_CONF_SAMPLERATE, SR_CONF_TRIGGER_TYPE, SR_CONF_CAPTURE_RATIO, SR_CONF_LIMIT_SAMPLES, SR_CONF_EXTERNAL_CLOCK, SR_CONF_PATTERN_MODE, SR_CONF_SWAP, SR_CONF_RLE, }; #define STR_PATTERN_NONE "None" #define STR_PATTERN_EXTERNAL "External" #define STR_PATTERN_INTERNAL "Internal" /* Supported methods of test pattern outputs */ enum { /** * Capture pins 31:16 (unbuffered wing) output a test pattern * that can captured on pins 0:15. */ PATTERN_EXTERNAL, /** Route test pattern internally to capture buffer. */ PATTERN_INTERNAL, }; static const char *patterns[] = { STR_PATTERN_NONE, STR_PATTERN_EXTERNAL, STR_PATTERN_INTERNAL, }; /* Channels are numbered 0-31 (on the PCB silkscreen). */ SR_PRIV const char *ols_channel_names[NUM_CHANNELS + 1] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", NULL, }; /* Default supported samplerates, can be overridden by device metadata. */ static const uint64_t samplerates[] = { SR_HZ(10), SR_MHZ(200), SR_HZ(1), }; SR_PRIV struct sr_dev_driver ols_driver_info; static struct sr_dev_driver *di = &ols_driver_info; static int init(struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { struct sr_config *src; struct sr_dev_inst *sdi; struct drv_context *drvc; struct dev_context *devc; struct sr_channel *ch; struct sr_serial_dev_inst *serial; GPollFD probefd; GSList *l, *devices; int ret, i; const char *conn, *serialcomm; char buf[8]; drvc = di->priv; devices = NULL; conn = serialcomm = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; case SR_CONF_SERIALCOMM: serialcomm = g_variant_get_string(src->data, NULL); break; } } if (!conn) return NULL; if (serialcomm == NULL) serialcomm = SERIALCOMM; if (!(serial = sr_serial_dev_inst_new(conn, serialcomm))) return NULL; /* The discovery procedure is like this: first send the Reset * command (0x00) 5 times, since the device could be anywhere * in a 5-byte command. Then send the ID command (0x02). * If the device responds with 4 bytes ("OLS1" or "SLA1"), we * have a match. */ sr_info("Probing %s.", conn); if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return NULL; ret = SR_OK; for (i = 0; i < 5; i++) { if ((ret = send_shortcommand(serial, CMD_RESET)) != SR_OK) { sr_err("Port %s is not writable.", conn); break; } } if (ret != SR_OK) { serial_close(serial); sr_err("Could not use port %s. Quitting.", conn); return NULL; } send_shortcommand(serial, CMD_ID); /* Wait 10ms for a response. */ g_usleep(10000); sp_get_port_handle(serial->data, &probefd.fd); probefd.events = G_IO_IN; g_poll(&probefd, 1, 1); if (probefd.revents != G_IO_IN) return NULL; if (serial_read_blocking(serial, buf, 4) != 4) return NULL; if (strncmp(buf, "1SLO", 4) && strncmp(buf, "1ALS", 4)) return NULL; /* Definitely using the OLS protocol, check if it supports * the metadata command. */ send_shortcommand(serial, CMD_METADATA); if (g_poll(&probefd, 1, 10) > 0) { /* Got metadata. */ sdi = get_metadata(serial); sdi->index = 0; devc = sdi->priv; } else { /* Not an OLS -- some other board that uses the sump protocol. */ sr_info("Device does not support metadata."); sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Sump", "Logic Analyzer", "v1.0"); sdi->driver = di; for (i = 0; i < 32; i++) { if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, ols_channel_names[i]))) return 0; sdi->channels = g_slist_append(sdi->channels, ch); } devc = ols_dev_new(); sdi->priv = devc; } /* Configure samplerate and divider. */ if (ols_set_samplerate(sdi, DEFAULT_SAMPLERATE) != SR_OK) sr_dbg("Failed to set default samplerate (%"PRIu64").", DEFAULT_SAMPLERATE); /* Clear trigger masks, values and stages. */ ols_configure_channels(sdi); sdi->inst_type = SR_INST_SERIAL; sdi->conn = serial; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); serial_close(serial); return devices; } static GSList *dev_list(void) { return ((struct drv_context *)(di->priv))->instances; } static int cleanup(void) { return std_dev_clear(di, NULL); } static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; (void)cg; if (!sdi) return SR_ERR_ARG; devc = sdi->priv; switch (id) { case SR_CONF_SAMPLERATE: *data = g_variant_new_uint64(devc->cur_samplerate); break; case SR_CONF_CAPTURE_RATIO: *data = g_variant_new_uint64(devc->capture_ratio); break; case SR_CONF_LIMIT_SAMPLES: *data = g_variant_new_uint64(devc->limit_samples); break; case SR_CONF_PATTERN_MODE: if (devc->flag_reg & FLAG_EXTERNAL_TEST_MODE) *data = g_variant_new_string(STR_PATTERN_EXTERNAL); else if (devc->flag_reg & FLAG_INTERNAL_TEST_MODE) *data = g_variant_new_string(STR_PATTERN_INTERNAL); else *data = g_variant_new_string(STR_PATTERN_NONE); break; case SR_CONF_RLE: *data = g_variant_new_boolean(devc->flag_reg & FLAG_RLE ? TRUE : FALSE); break; default: return SR_ERR_NA; } return SR_OK; } static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; uint16_t flag; uint64_t tmp_u64; int ret; const char *stropt; (void)cg; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; switch (id) { case SR_CONF_SAMPLERATE: tmp_u64 = g_variant_get_uint64(data); if (tmp_u64 < samplerates[0] || tmp_u64 > samplerates[1]) return SR_ERR_SAMPLERATE; ret = ols_set_samplerate(sdi, g_variant_get_uint64(data)); break; case SR_CONF_LIMIT_SAMPLES: tmp_u64 = g_variant_get_uint64(data); if (tmp_u64 < MIN_NUM_SAMPLES) return SR_ERR; devc->limit_samples = tmp_u64; ret = SR_OK; break; case SR_CONF_CAPTURE_RATIO: devc->capture_ratio = g_variant_get_uint64(data); if (devc->capture_ratio < 0 || devc->capture_ratio > 100) { devc->capture_ratio = 0; ret = SR_ERR; } else ret = SR_OK; break; case SR_CONF_EXTERNAL_CLOCK: if (g_variant_get_boolean(data)) { sr_info("Enabling external clock."); devc->flag_reg |= FLAG_CLOCK_EXTERNAL; } else { sr_info("Disabled external clock."); devc->flag_reg &= ~FLAG_CLOCK_EXTERNAL; } ret = SR_OK; break; case SR_CONF_PATTERN_MODE: stropt = g_variant_get_string(data, NULL); ret = SR_OK; flag = 0xffff; if (!strcmp(stropt, STR_PATTERN_NONE)) { sr_info("Disabling test modes."); flag = 0x0000; }else if (!strcmp(stropt, STR_PATTERN_INTERNAL)) { sr_info("Enabling internal test mode."); flag = FLAG_INTERNAL_TEST_MODE; } else if (!strcmp(stropt, STR_PATTERN_EXTERNAL)) { sr_info("Enabling external test mode."); flag = FLAG_EXTERNAL_TEST_MODE; } else { ret = SR_ERR; } if (flag != 0xffff) { devc->flag_reg &= ~(FLAG_INTERNAL_TEST_MODE | FLAG_EXTERNAL_TEST_MODE); devc->flag_reg |= flag; } break; case SR_CONF_SWAP: if (g_variant_get_boolean(data)) { sr_info("Enabling channel swapping."); devc->flag_reg |= FLAG_SWAP_CHANNELS; } else { sr_info("Disabling channel swapping."); devc->flag_reg &= ~FLAG_SWAP_CHANNELS; } ret = SR_OK; break; case SR_CONF_RLE: if (g_variant_get_boolean(data)) { sr_info("Enabling RLE."); devc->flag_reg |= FLAG_RLE; } else { sr_info("Disabling RLE."); devc->flag_reg &= ~FLAG_RLE; } ret = SR_OK; break; default: ret = SR_ERR_NA; } return ret; } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; GVariant *gvar, *grange[2]; GVariantBuilder gvb; int num_channels, i; (void)cg; switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); break; case SR_CONF_DEVICE_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); break; 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)); g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar); *data = g_variant_builder_end(&gvb); break; case SR_CONF_TRIGGER_TYPE: *data = g_variant_new_string(TRIGGER_TYPE); break; case SR_CONF_PATTERN_MODE: *data = g_variant_new_strv(patterns, ARRAY_SIZE(patterns)); break; case SR_CONF_LIMIT_SAMPLES: if (!sdi) return SR_ERR_ARG; devc = sdi->priv; if (devc->flag_reg & FLAG_RLE) return SR_ERR_NA; if (devc->max_samples == 0) /* Device didn't specify sample memory size in metadata. */ return SR_ERR_NA; /* * Channel groups are turned off if no channels in that group are * enabled, making more room for samples for the enabled group. */ ols_configure_channels(sdi); num_channels = 0; for (i = 0; i < 4; i++) { if (devc->channel_mask & (0xff << (i * 8))) num_channels++; } if (num_channels == 0) { /* This can happen, but shouldn't cause too much drama. * However we can't continue because the code below would * divide by zero. */ break; } grange[0] = g_variant_new_uint64(MIN_NUM_SAMPLES); grange[1] = g_variant_new_uint64(devc->max_samples / num_channels); *data = g_variant_new_tuple(grange, 2); break; default: return SR_ERR_NA; } return SR_OK; } static int set_trigger(const struct sr_dev_inst *sdi, int stage) { struct dev_context *devc; struct sr_serial_dev_inst *serial; uint8_t cmd, arg[4]; devc = sdi->priv; serial = sdi->conn; cmd = CMD_SET_TRIGGER_MASK + stage * 4; arg[0] = devc->trigger_mask[stage] & 0xff; arg[1] = (devc->trigger_mask[stage] >> 8) & 0xff; arg[2] = (devc->trigger_mask[stage] >> 16) & 0xff; arg[3] = (devc->trigger_mask[stage] >> 24) & 0xff; if (send_longcommand(serial, cmd, arg) != SR_OK) return SR_ERR; cmd = CMD_SET_TRIGGER_VALUE + stage * 4; arg[0] = devc->trigger_value[stage] & 0xff; arg[1] = (devc->trigger_value[stage] >> 8) & 0xff; arg[2] = (devc->trigger_value[stage] >> 16) & 0xff; arg[3] = (devc->trigger_value[stage] >> 24) & 0xff; if (send_longcommand(serial, cmd, arg) != SR_OK) return SR_ERR; cmd = CMD_SET_TRIGGER_CONFIG + stage * 4; arg[0] = arg[1] = arg[3] = 0x00; arg[2] = stage; if (stage == devc->num_stages) /* Last stage, fire when this one matches. */ arg[3] |= TRIGGER_START; if (send_longcommand(serial, cmd, arg) != SR_OK) return SR_ERR; return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *devc; struct sr_serial_dev_inst *serial; uint16_t samplecount, readcount, delaycount; uint8_t changrp_mask, arg[4]; int num_channels; int ret, i; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; devc = sdi->priv; serial = sdi->conn; if (ols_configure_channels(sdi) != SR_OK) { sr_err("Failed to configure channels."); return SR_ERR; } /* * Enable/disable channel groups in the flag register according to the * channel mask. Calculate this here, because num_channels is needed * to limit readcount. */ changrp_mask = 0; num_channels = 0; for (i = 0; i < 4; i++) { if (devc->channel_mask & (0xff << (i * 8))) { changrp_mask |= (1 << i); num_channels++; } } /* * Limit readcount to prevent reading past the end of the hardware * buffer. */ samplecount = MIN(devc->max_samples / num_channels, devc->limit_samples); readcount = samplecount / 4; /* Rather read too many samples than too few. */ if (samplecount % 4 != 0) readcount++; /* Basic triggers. */ if (devc->trigger_mask[0] != 0x00000000) { /* At least one channel has a trigger on it. */ delaycount = readcount * (1 - devc->capture_ratio / 100.0); devc->trigger_at = (readcount - delaycount) * 4 - devc->num_stages; for (i = 0; i <= devc->num_stages; i++) { sr_dbg("Setting stage %d trigger.", i); if ((ret = set_trigger(sdi, i)) != SR_OK) return ret; } } else { /* No triggers configured, force trigger on first stage. */ sr_dbg("Forcing trigger at stage 0."); if ((ret = set_trigger(sdi, 0)) != SR_OK) return ret; delaycount = readcount; } /* Samplerate. */ sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)", devc->cur_samplerate, devc->cur_samplerate_divider); arg[0] = devc->cur_samplerate_divider & 0xff; arg[1] = (devc->cur_samplerate_divider & 0xff00) >> 8; arg[2] = (devc->cur_samplerate_divider & 0xff0000) >> 16; arg[3] = 0x00; if (send_longcommand(serial, CMD_SET_DIVIDER, arg) != SR_OK) return SR_ERR; /* Send sample limit and pre/post-trigger capture ratio. */ sr_dbg("Setting sample limit %d, trigger point at %d", (readcount - 1) * 4, (delaycount - 1) * 4); arg[0] = ((readcount - 1) & 0xff); arg[1] = ((readcount - 1) & 0xff00) >> 8; arg[2] = ((delaycount - 1) & 0xff); arg[3] = ((delaycount - 1) & 0xff00) >> 8; if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK) return SR_ERR; /* Flag register. */ sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s", devc->flag_reg & FLAG_INTERNAL_TEST_MODE ? "on": "off", devc->flag_reg & FLAG_EXTERNAL_TEST_MODE ? "on": "off", devc->flag_reg & FLAG_RLE ? "on" : "off", devc->flag_reg & FLAG_FILTER ? "on": "off", devc->flag_reg & FLAG_DEMUX ? "on" : "off"); /* 1 means "disable channel". */ devc->flag_reg |= ~(changrp_mask << 2) & 0x3c; arg[0] = devc->flag_reg & 0xff; arg[1] = devc->flag_reg >> 8; arg[2] = arg[3] = 0x00; if (send_longcommand(serial, CMD_SET_FLAGS, arg) != SR_OK) return SR_ERR; /* Start acquisition on the device. */ if (send_shortcommand(serial, CMD_RUN) != SR_OK) return SR_ERR; /* Reset all operational states. */ devc->rle_count = devc->num_transfers = 0; devc->num_samples = devc->num_bytes = 0; devc->cnt_bytes = devc->cnt_samples = devc->cnt_samples_rle = 0; memset(devc->sample, 0, 4); /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); serial_source_add(serial, G_IO_IN, -1, ols_receive_data, cb_data); return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; abort_acquisition(sdi); return SR_OK; } SR_PRIV struct sr_dev_driver ols_driver_info = { .name = "ols", .longname = "Openbench Logic Sniffer", .api_version = 1, .init = init, .cleanup = cleanup, .scan = scan, .dev_list = dev_list, .dev_clear = NULL, .config_get = config_get, .config_set = config_set, .config_list = config_list, .dev_open = std_serial_dev_open, .dev_close = std_serial_dev_close, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, .priv = NULL, }; libsigrok-0.3.0/hardware/common/0000755000175000017500000000000012332246734013573 500000000000000libsigrok-0.3.0/hardware/common/usb.c0000644000175000017500000001617512332246667014467 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2012 Uwe Hermann * Copyright (C) 2012 Bert Vermeulen * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" /* SR_CONF_CONN takes one of these: */ #define CONN_USB_VIDPID "^([0-9a-z]{4})\\.([0-9a-z]{4})$" #define CONN_USB_BUSADDR "^(\\d+)\\.(\\d+)$" #define LOG_PREFIX "usb" /** * Find USB devices according to a connection string. * * @param usb_ctx libusb context to use while scanning. * @param conn Connection string specifying the device(s) to match. This * can be of the form ".
", or ".". * * @return A GSList of struct sr_usb_dev_inst, with bus and address fields * matching the device that matched the connection string. The GSList and * its contents must be freed by the caller. */ SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn) { struct sr_usb_dev_inst *usb; struct libusb_device **devlist; struct libusb_device_descriptor des; GSList *devices; GRegex *reg; GMatchInfo *match; int vid, pid, bus, addr, b, a, ret, i; char *mstr; vid = pid = bus = addr = 0; reg = g_regex_new(CONN_USB_VIDPID, 0, 0, NULL); if (g_regex_match(reg, conn, 0, &match)) { if ((mstr = g_match_info_fetch(match, 1))) vid = strtoul(mstr, NULL, 16); g_free(mstr); if ((mstr = g_match_info_fetch(match, 2))) pid = strtoul(mstr, NULL, 16); g_free(mstr); sr_dbg("Trying to find USB device with VID:PID = %04x:%04x.", vid, pid); } else { g_match_info_unref(match); g_regex_unref(reg); reg = g_regex_new(CONN_USB_BUSADDR, 0, 0, NULL); if (g_regex_match(reg, conn, 0, &match)) { if ((mstr = g_match_info_fetch(match, 1))) bus = strtoul(mstr, NULL, 10); g_free(mstr); if ((mstr = g_match_info_fetch(match, 2))) addr = strtoul(mstr, NULL, 10); g_free(mstr); sr_dbg("Trying to find USB device with bus.address = " "%d.%d.", bus, addr); } } g_match_info_unref(match); g_regex_unref(reg); if (vid + pid + bus + addr == 0) { sr_err("Neither VID:PID nor bus.address was specified."); return NULL; } if (bus > 64) { sr_err("Invalid bus specified: %d.", bus); return NULL; } if (addr > 127) { sr_err("Invalid address specified: %d.", addr); return NULL; } /* Looks like a valid USB device specification, but is it connected? */ devices = NULL; libusb_get_device_list(usb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if ((ret = libusb_get_device_descriptor(devlist[i], &des))) { sr_err("Failed to get device descriptor: %s.", libusb_error_name(ret)); continue; } if (vid + pid && (des.idVendor != vid || des.idProduct != pid)) continue; b = libusb_get_bus_number(devlist[i]); a = libusb_get_device_address(devlist[i]); if (bus + addr && (b != bus || a != addr)) continue; sr_dbg("Found USB device (VID:PID = %04x:%04x, bus.address = " "%d.%d).", des.idVendor, des.idProduct, b, a); usb = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); devices = g_slist_append(devices, usb); } libusb_free_device_list(devlist, 1); sr_dbg("Found %d device(s).", g_slist_length(devices)); return devices; } SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb) { struct libusb_device **devlist; struct libusb_device_descriptor des; int ret, r, cnt, i, a, b; sr_dbg("Trying to open USB device %d.%d.", usb->bus, usb->address); if ((cnt = libusb_get_device_list(usb_ctx, &devlist)) < 0) { sr_err("Failed to retrieve device list: %s.", libusb_error_name(cnt)); return SR_ERR; } ret = SR_ERR; for (i = 0; i < cnt; i++) { if ((r = libusb_get_device_descriptor(devlist[i], &des)) < 0) { sr_err("Failed to get device descriptor: %s.", libusb_error_name(r)); continue; } b = libusb_get_bus_number(devlist[i]); a = libusb_get_device_address(devlist[i]); if (b != usb->bus || a != usb->address) continue; if ((r = libusb_open(devlist[i], &usb->devhdl)) < 0) { sr_err("Failed to open device: %s.", libusb_error_name(r)); break; } sr_dbg("Opened USB device (VID:PID = %04x:%04x, bus.address = " "%d.%d).", des.idVendor, des.idProduct, b, a); ret = SR_OK; break; } libusb_free_device_list(devlist, 1); return ret; } #ifdef _WIN32 static gpointer usb_thread(gpointer data) { struct sr_context *ctx = data; while (ctx->usb_thread_running) { g_mutex_lock(&ctx->usb_mutex); libusb_wait_for_event(ctx->libusb_ctx, NULL); SetEvent(ctx->usb_event); g_mutex_unlock(&ctx->usb_mutex); g_thread_yield(); } return NULL; } static int usb_callback(int fd, int revents, void *cb_data) { struct sr_context *ctx = cb_data; int ret; g_mutex_lock(&ctx->usb_mutex); ret = ctx->usb_cb(fd, revents, ctx->usb_cb_data); if (ctx->usb_thread_running) { ResetEvent(ctx->usb_event); g_mutex_unlock(&ctx->usb_mutex); } return ret; } #endif SR_PRIV int usb_source_add(struct sr_context *ctx, int timeout, sr_receive_data_callback cb, void *cb_data) { if (ctx->usb_source_present) { sr_err("A USB event source is already present."); return SR_ERR; } #ifdef _WIN32 ctx->usb_event = CreateEvent(NULL, TRUE, FALSE, NULL); g_mutex_init(&ctx->usb_mutex); ctx->usb_thread_running = TRUE; ctx->usb_thread = g_thread_new("usb", usb_thread, ctx); ctx->usb_pollfd.fd = ctx->usb_event; ctx->usb_pollfd.events = G_IO_IN; ctx->usb_cb = cb; ctx->usb_cb_data = cb_data; sr_session_source_add_pollfd(&ctx->usb_pollfd, timeout, usb_callback, ctx); #else const struct libusb_pollfd **lupfd; unsigned int i; lupfd = libusb_get_pollfds(ctx->libusb_ctx); for (i = 0; lupfd[i]; i++) sr_source_add(lupfd[i]->fd, lupfd[i]->events, timeout, cb, cb_data); free(lupfd); #endif ctx->usb_source_present = TRUE; return SR_OK; } SR_PRIV int usb_source_remove(struct sr_context *ctx) { if (!ctx->usb_source_present) return SR_OK; #ifdef _WIN32 ctx->usb_thread_running = FALSE; g_mutex_unlock(&ctx->usb_mutex); libusb_unlock_events(ctx->libusb_ctx); g_thread_join(ctx->usb_thread); g_mutex_clear(&ctx->usb_mutex); sr_session_source_remove_pollfd(&ctx->usb_pollfd); CloseHandle(ctx->usb_event); #else const struct libusb_pollfd **lupfd; unsigned int i; lupfd = libusb_get_pollfds(ctx->libusb_ctx); for (i = 0; lupfd[i]; i++) sr_source_remove(lupfd[i]->fd); free(lupfd); #endif ctx->usb_source_present = FALSE; return SR_OK; } libsigrok-0.3.0/hardware/common/scpi_serial.c0000644000175000017500000001356512332246667016173 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 poljar (Damir Jelić) * Copyright (C) 2013 Martin Ling * * 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 . */ #include "libsigrok.h" #include "libsigrok-internal.h" #include #include #include #define LOG_PREFIX "scpi_serial" #define BUFFER_SIZE 1024 struct scpi_serial { struct sr_serial_dev_inst *serial; char buffer[BUFFER_SIZE]; size_t count; size_t read; }; static struct { uint16_t vendor_id; uint16_t product_id; const char *serialcomm; } scpi_serial_usb_ids[] = { { 0x0403, 0xed72, "115200/8n1/flow=1" }, /* Hameg HO720 */ { 0x0403, 0xed73, "115200/8n1/flow=1" }, /* Hameg HO730 */ }; static GSList *scpi_serial_scan(struct drv_context *drvc) { GSList *l, *r, *resources = NULL; gchar *res; unsigned i; (void)drvc; for (i = 0; i < ARRAY_SIZE(scpi_serial_usb_ids); i++) { if ((l = sr_serial_find_usb(scpi_serial_usb_ids[i].vendor_id, scpi_serial_usb_ids[i].product_id)) == NULL) continue; for (r = l; r; r = r->next) { if (scpi_serial_usb_ids[i].serialcomm) res = g_strdup_printf("%s:%s", (char *) r->data, scpi_serial_usb_ids[i].serialcomm); else res = g_strdup(r->data); resources = g_slist_append(resources, res); } g_slist_free_full(l, g_free); } return resources; } static int scpi_serial_dev_inst_new(void *priv, struct drv_context *drvc, const char *resource, char **params, const char *serialcomm) { struct scpi_serial *sscpi = priv; (void)drvc; (void)params; if (!(sscpi->serial = sr_serial_dev_inst_new(resource, serialcomm))) return SR_ERR; return SR_OK; } static int scpi_serial_open(void *priv) { struct scpi_serial *sscpi = priv; struct sr_serial_dev_inst *serial = sscpi->serial; if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return SR_ERR; if (serial_flush(serial) != SR_OK) return SR_ERR; sscpi->count = 0; sscpi->read = 0; return SR_OK; } static int scpi_serial_source_add(void *priv, int events, int timeout, sr_receive_data_callback cb, void *cb_data) { struct scpi_serial *sscpi = priv; struct sr_serial_dev_inst *serial = sscpi->serial; return serial_source_add(serial, events, timeout, cb, cb_data); } static int scpi_serial_source_remove(void *priv) { struct scpi_serial *sscpi = priv; struct sr_serial_dev_inst *serial = sscpi->serial; return serial_source_remove(serial); } static int scpi_serial_send(void *priv, const char *command) { int len, result, written; gchar *terminated_command; struct scpi_serial *sscpi = priv; struct sr_serial_dev_inst *serial = sscpi->serial; terminated_command = g_strconcat(command, "\n", NULL); len = strlen(terminated_command); written = 0; while (written < len) { result = serial_write(serial, terminated_command + written, len - written); if (result < 0) { sr_err("Error while sending SCPI command: '%s'.", command); g_free(terminated_command); return SR_ERR; } written += result; } g_free(terminated_command); sr_spew("Successfully sent SCPI command: '%s'.", command); return SR_OK; } static int scpi_serial_read_begin(void *priv) { (void) priv; return SR_OK; } static int scpi_serial_read_data(void *priv, char *buf, int maxlen) { struct scpi_serial *sscpi = priv; int len, ret; len = BUFFER_SIZE - sscpi->count; /* Try to read new data into the buffer if there is space. */ if (len > 0) { ret = serial_read(sscpi->serial, sscpi->buffer + sscpi->read, BUFFER_SIZE - sscpi->count); if (ret < 0) return ret; sscpi->count += ret; if (ret > 0) sr_spew("Read %d bytes into buffer.", ret); } /* Return as many bytes as possible from buffer, excluding any trailing newline. */ if (sscpi->read < sscpi->count) { len = sscpi->count - sscpi->read; if (len > maxlen) len = maxlen; if (sscpi->buffer[sscpi->read + len - 1] == '\n') len--; sr_spew("Returning %d bytes from buffer.", len); memcpy(buf, sscpi->buffer + sscpi->read, len); sscpi->read += len; if (sscpi->read == BUFFER_SIZE) { sr_spew("Resetting buffer."); sscpi->count = 0; sscpi->read = 0; } return len; } return 0; } static int scpi_serial_read_complete(void *priv) { struct scpi_serial *sscpi = priv; /* If the next character is a newline, discard it and report complete. */ if (sscpi->read < sscpi->count && sscpi->buffer[sscpi->read] == '\n') { sscpi->read++; return 1; } else { return 0; } } static int scpi_serial_close(void *priv) { struct scpi_serial *sscpi = priv; return serial_close(sscpi->serial); } static void scpi_serial_free(void *priv) { struct scpi_serial *sscpi = priv; sr_serial_dev_inst_free(sscpi->serial); } SR_PRIV const struct sr_scpi_dev_inst scpi_serial_dev = { .name = "serial", .prefix = "", .priv_size = sizeof(struct scpi_serial), .scan = scpi_serial_scan, .dev_inst_new = scpi_serial_dev_inst_new, .open = scpi_serial_open, .source_add = scpi_serial_source_add, .source_remove = scpi_serial_source_remove, .send = scpi_serial_send, .read_begin = scpi_serial_read_begin, .read_data = scpi_serial_read_data, .read_complete = scpi_serial_read_complete, .close = scpi_serial_close, .free = scpi_serial_free, }; libsigrok-0.3.0/hardware/common/vxi_xdr.c0000644000175000017500000002542612332246667015360 00000000000000/* * Please do not edit this file. * It was generated using rpcgen. */ #include "vxi.h" bool_t xdr_Device_Link (XDR *xdrs, Device_Link *objp) { if (!xdr_long (xdrs, objp)) return FALSE; return TRUE; } bool_t xdr_Device_AddrFamily (XDR *xdrs, Device_AddrFamily *objp) { if (!xdr_enum (xdrs, (enum_t *) objp)) return FALSE; return TRUE; } bool_t xdr_Device_Flags (XDR *xdrs, Device_Flags *objp) { if (!xdr_long (xdrs, objp)) return FALSE; return TRUE; } bool_t xdr_Device_ErrorCode (XDR *xdrs, Device_ErrorCode *objp) { if (!xdr_long (xdrs, objp)) return FALSE; return TRUE; } bool_t xdr_Device_Error (XDR *xdrs, Device_Error *objp) { if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; return TRUE; } bool_t xdr_Create_LinkParms (XDR *xdrs, Create_LinkParms *objp) { register int32_t *buf; if (xdrs->x_op == XDR_ENCODE) { buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_long (xdrs, &objp->clientId)) return FALSE; if (!xdr_bool (xdrs, &objp->lockDevice)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; } else { IXDR_PUT_LONG(buf, objp->clientId); IXDR_PUT_BOOL(buf, objp->lockDevice); IXDR_PUT_U_LONG(buf, objp->lock_timeout); } if (!xdr_string (xdrs, &objp->device, ~0)) return FALSE; return TRUE; } else if (xdrs->x_op == XDR_DECODE) { buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_long (xdrs, &objp->clientId)) return FALSE; if (!xdr_bool (xdrs, &objp->lockDevice)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; } else { objp->clientId = IXDR_GET_LONG(buf); objp->lockDevice = IXDR_GET_BOOL(buf); objp->lock_timeout = IXDR_GET_U_LONG(buf); } if (!xdr_string (xdrs, &objp->device, ~0)) return FALSE; return TRUE; } if (!xdr_long (xdrs, &objp->clientId)) return FALSE; if (!xdr_bool (xdrs, &objp->lockDevice)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_string (xdrs, &objp->device, ~0)) return FALSE; return TRUE; } bool_t xdr_Create_LinkResp (XDR *xdrs, Create_LinkResp *objp) { if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_u_short (xdrs, &objp->abortPort)) return FALSE; if (!xdr_u_long (xdrs, &objp->maxRecvSize)) return FALSE; return TRUE; } bool_t xdr_Device_WriteParms (XDR *xdrs, Device_WriteParms *objp) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_u_long (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) return FALSE; return TRUE; } bool_t xdr_Device_WriteResp (XDR *xdrs, Device_WriteResp *objp) { if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_u_long (xdrs, &objp->size)) return FALSE; return TRUE; } bool_t xdr_Device_ReadParms (XDR *xdrs, Device_ReadParms *objp) { register int32_t *buf; if (xdrs->x_op == XDR_ENCODE) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_long (xdrs, &objp->requestSize)) return FALSE; if (!xdr_u_long (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; } else { IXDR_PUT_U_LONG(buf, objp->requestSize); IXDR_PUT_U_LONG(buf, objp->io_timeout); IXDR_PUT_U_LONG(buf, objp->lock_timeout); } if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_char (xdrs, &objp->termChar)) return FALSE; return TRUE; } else if (xdrs->x_op == XDR_DECODE) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_long (xdrs, &objp->requestSize)) return FALSE; if (!xdr_u_long (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; } else { objp->requestSize = IXDR_GET_U_LONG(buf); objp->io_timeout = IXDR_GET_U_LONG(buf); objp->lock_timeout = IXDR_GET_U_LONG(buf); } if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_char (xdrs, &objp->termChar)) return FALSE; return TRUE; } if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_u_long (xdrs, &objp->requestSize)) return FALSE; if (!xdr_u_long (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_char (xdrs, &objp->termChar)) return FALSE; return TRUE; } bool_t xdr_Device_ReadResp (XDR *xdrs, Device_ReadResp *objp) { if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_long (xdrs, &objp->reason)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) return FALSE; return TRUE; } bool_t xdr_Device_ReadStbResp (XDR *xdrs, Device_ReadStbResp *objp) { if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_u_char (xdrs, &objp->stb)) return FALSE; return TRUE; } bool_t xdr_Device_GenericParms (XDR *xdrs, Device_GenericParms *objp) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_u_long (xdrs, &objp->io_timeout)) return FALSE; return TRUE; } bool_t xdr_Device_RemoteFunc (XDR *xdrs, Device_RemoteFunc *objp) { register int32_t *buf; if (xdrs->x_op == XDR_ENCODE) { buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_long (xdrs, &objp->hostAddr)) return FALSE; if (!xdr_u_short (xdrs, &objp->hostPort)) return FALSE; if (!xdr_u_long (xdrs, &objp->progNum)) return FALSE; if (!xdr_u_long (xdrs, &objp->progVers)) return FALSE; } else { IXDR_PUT_U_LONG(buf, objp->hostAddr); IXDR_PUT_U_SHORT(buf, objp->hostPort); IXDR_PUT_U_LONG(buf, objp->progNum); IXDR_PUT_U_LONG(buf, objp->progVers); } if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) return FALSE; return TRUE; } else if (xdrs->x_op == XDR_DECODE) { buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_long (xdrs, &objp->hostAddr)) return FALSE; if (!xdr_u_short (xdrs, &objp->hostPort)) return FALSE; if (!xdr_u_long (xdrs, &objp->progNum)) return FALSE; if (!xdr_u_long (xdrs, &objp->progVers)) return FALSE; } else { objp->hostAddr = IXDR_GET_U_LONG(buf); objp->hostPort = IXDR_GET_U_SHORT(buf); objp->progNum = IXDR_GET_U_LONG(buf); objp->progVers = IXDR_GET_U_LONG(buf); } if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) return FALSE; return TRUE; } if (!xdr_u_long (xdrs, &objp->hostAddr)) return FALSE; if (!xdr_u_short (xdrs, &objp->hostPort)) return FALSE; if (!xdr_u_long (xdrs, &objp->progNum)) return FALSE; if (!xdr_u_long (xdrs, &objp->progVers)) return FALSE; if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) return FALSE; return TRUE; } bool_t xdr_Device_EnableSrqParms (XDR *xdrs, Device_EnableSrqParms *objp) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_bool (xdrs, &objp->enable)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, 40)) return FALSE; return TRUE; } bool_t xdr_Device_LockParms (XDR *xdrs, Device_LockParms *objp) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; return TRUE; } bool_t xdr_Device_DocmdParms (XDR *xdrs, Device_DocmdParms *objp) { register int32_t *buf; if (xdrs->x_op == XDR_ENCODE) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_long (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_long (xdrs, &objp->cmd)) return FALSE; if (!xdr_bool (xdrs, &objp->network_order)) return FALSE; if (!xdr_long (xdrs, &objp->datasize)) return FALSE; } else { IXDR_PUT_U_LONG(buf, objp->io_timeout); IXDR_PUT_U_LONG(buf, objp->lock_timeout); IXDR_PUT_LONG(buf, objp->cmd); IXDR_PUT_BOOL(buf, objp->network_order); IXDR_PUT_LONG(buf, objp->datasize); } if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) return FALSE; return TRUE; } else if (xdrs->x_op == XDR_DECODE) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_long (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_long (xdrs, &objp->cmd)) return FALSE; if (!xdr_bool (xdrs, &objp->network_order)) return FALSE; if (!xdr_long (xdrs, &objp->datasize)) return FALSE; } else { objp->io_timeout = IXDR_GET_U_LONG(buf); objp->lock_timeout = IXDR_GET_U_LONG(buf); objp->cmd = IXDR_GET_LONG(buf); objp->network_order = IXDR_GET_BOOL(buf); objp->datasize = IXDR_GET_LONG(buf); } if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) return FALSE; return TRUE; } if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_u_long (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_long (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_long (xdrs, &objp->cmd)) return FALSE; if (!xdr_bool (xdrs, &objp->network_order)) return FALSE; if (!xdr_long (xdrs, &objp->datasize)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) return FALSE; return TRUE; } bool_t xdr_Device_DocmdResp (XDR *xdrs, Device_DocmdResp *objp) { if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->data_out.data_out_val, (u_int *) &objp->data_out.data_out_len, ~0)) return FALSE; return TRUE; } bool_t xdr_Device_SrqParms (XDR *xdrs, Device_SrqParms *objp) { if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, ~0)) return FALSE; return TRUE; } libsigrok-0.3.0/hardware/common/scpi_visa.c0000644000175000017500000000751112332246667015650 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2013 Martin Ling * * 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 . */ #include "libsigrok.h" #include "libsigrok-internal.h" #include #include #define LOG_PREFIX "scpi_visa" struct scpi_visa { char *resource; ViSession rmgr; ViSession vi; }; static int scpi_visa_dev_inst_new(void *priv, struct drv_context *drvc, const char *resource, char **params, const char *serialcomm) { struct scpi_visa *vscpi = priv; (void)drvc; (void)resource; (void)serialcomm; if (!params || !params[1]) { sr_err("Invalid parameters."); return SR_ERR_BUG; } vscpi->resource = g_strdup(params[1]); return SR_OK; } static int scpi_visa_open(void *priv) { struct scpi_visa *vscpi = priv; if (viOpenDefaultRM(&vscpi->rmgr) != VI_SUCCESS) { sr_err("Cannot open default resource manager."); return SR_ERR; } if (viOpen(vscpi->rmgr, vscpi->resource, VI_NO_LOCK, 0, &vscpi->vi) != VI_SUCCESS) { sr_err("Cannot open resource."); return SR_ERR; } return SR_OK; } static int scpi_visa_source_add(void *priv, int events, int timeout, sr_receive_data_callback cb, void *cb_data) { (void) priv; /* Hook up a dummy handler to receive data from the device. */ return sr_source_add(-1, events, timeout, cb, cb_data); } static int scpi_visa_source_remove(void *priv) { (void) priv; return sr_source_remove(-1); } static int scpi_visa_send(void *priv, const char *command) { struct scpi_visa *vscpi = priv; gchar *terminated_command; ViUInt32 written = 0; int len; terminated_command = g_strconcat(command, "\n", NULL); len = strlen(terminated_command); if (viWrite(vscpi->vi, (ViBuf) (terminated_command + written), len, &written) != VI_SUCCESS) { sr_err("Error while sending SCPI command: '%s'.", command); g_free(terminated_command); return SR_ERR; } g_free(terminated_command); sr_spew("Successfully sent SCPI command: '%s'.", command); return SR_OK; } static int scpi_visa_read_begin(void *priv) { (void) priv; return SR_OK; } static int scpi_visa_read_data(void *priv, char *buf, int maxlen) { struct scpi_visa *vscpi = priv; ViUInt32 count; if (viRead(vscpi->vi, (ViBuf) buf, maxlen, &count) != VI_SUCCESS) { sr_err("Read failed."); return SR_ERR; } return count; } static int scpi_visa_read_complete(void *priv) { struct scpi_visa *vscpi = priv; ViUInt16 status; if (viReadSTB(vscpi->vi, &status) != VI_SUCCESS) { sr_err("Failed to read status."); return SR_ERR; } return !(status & 16); } static int scpi_visa_close(void *priv) { struct scpi_visa *vscpi = priv; viClose(vscpi->vi); viClose(vscpi->rmgr); return SR_OK; } static void scpi_visa_free(void *priv) { struct scpi_visa *vscpi = priv; g_free(vscpi->resource); g_free(vscpi); } SR_PRIV const struct sr_scpi_dev_inst scpi_visa_dev = { .name = "VISA", .prefix = "visa", .priv_size = sizeof(struct scpi_visa), .dev_inst_new = scpi_visa_dev_inst_new, .open = scpi_visa_open, .source_add = scpi_visa_source_add, .source_remove = scpi_visa_source_remove, .send = scpi_visa_send, .read_begin = scpi_visa_read_begin, .read_data = scpi_visa_read_data, .read_complete = scpi_visa_read_complete, .close = scpi_visa_close, .free = scpi_visa_free, }; libsigrok-0.3.0/hardware/common/scpi_vxi.c0000644000175000017500000001436412332246667015520 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2014 Aurelien Jacobs * * Inspired by the VXI11 Ethernet Protocol for Linux: * http://optics.eee.nottingham.ac.uk/vxi11/ * * 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 . */ #include #include #include "vxi.h" #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "scpi_vxi" #define VXI_DEFAULT_TIMEOUT 2000 /* in ms */ struct scpi_vxi { char *address; char *instrument; CLIENT *client; Device_Link link; unsigned int max_send_size; unsigned int read_complete; }; static int scpi_vxi_dev_inst_new(void *priv, struct drv_context *drvc, const char *resource, char **params, const char *serialcomm) { struct scpi_vxi *vxi = priv; (void)drvc; (void)resource; (void)serialcomm; if (!params || !params[1]) { sr_err("Invalid parameters."); return SR_ERR; } vxi->address = g_strdup(params[1]); vxi->instrument = g_strdup(params[2] ? params[2] : "inst0"); return SR_OK; } static int scpi_vxi_open(void *priv) { struct scpi_vxi *vxi = priv; Create_LinkParms link_parms; Create_LinkResp *link_resp; vxi->client = clnt_create(vxi->address, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp"); if (vxi->client == NULL) { sr_err("Client creation failed for %s", vxi->address); return SR_ERR; } /* Set link parameters */ link_parms.clientId = (long) vxi->client; link_parms.lockDevice = 0; link_parms.lock_timeout = VXI_DEFAULT_TIMEOUT; link_parms.device = "inst0"; if (!(link_resp = create_link_1(&link_parms, vxi->client))) { sr_err("Link creation failed for %s", vxi->address); return SR_ERR; } vxi->link = link_resp->lid; vxi->max_send_size = link_resp->maxRecvSize; /* Set a default maxRecvSize for devices which do not specify it */ if (vxi->max_send_size <= 0) vxi->max_send_size = 4096; return SR_OK; } static int scpi_vxi_source_add(void *priv, int events, int timeout, sr_receive_data_callback cb, void *cb_data) { (void)priv; /* Hook up a dummy handler to receive data from the device. */ return sr_source_add(-1, events, timeout, cb, cb_data); } static int scpi_vxi_source_remove(void *priv) { (void)priv; return sr_source_remove(-1); } /* Operation Flags */ #define DF_WAITLOCK 0x01 /* wait if the operation is locked by another link */ #define DF_END 0x08 /* an END indicator is sent with last byte of buffer */ #define DF_TERM 0x80 /* a termination char is set during a read */ static int scpi_vxi_send(void *priv, const char *command) { struct scpi_vxi *vxi = priv; Device_WriteResp *write_resp; Device_WriteParms write_parms; char *terminated_command; unsigned int len; terminated_command = g_strdup_printf("%s\r\n", command); len = strlen(terminated_command); write_parms.lid = vxi->link; write_parms.io_timeout = VXI_DEFAULT_TIMEOUT; write_parms.lock_timeout = VXI_DEFAULT_TIMEOUT; write_parms.flags = DF_END; write_parms.data.data_len = MIN(len, vxi->max_send_size); write_parms.data.data_val = terminated_command; if (!(write_resp = device_write_1(&write_parms, vxi->client)) || write_resp->error) { sr_err("Device write failed for %s with error %d", vxi->address, write_resp->error); return SR_ERR; } g_free(terminated_command); if (write_resp->size < len) sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.", write_resp->size, len, command); else sr_spew("Successfully sent SCPI command: '%s'.", command); return SR_OK; } static int scpi_vxi_read_begin(void *priv) { struct scpi_vxi *vxi = priv; vxi->read_complete = 0; return SR_OK; } /* Read Response Reason Flags */ #define RRR_SIZE 0x01 /* requestSize bytes have been transferred */ #define RRR_TERM 0x02 /* a termination char has been read */ #define RRR_END 0x04 /* an END indicator has been read */ static int scpi_vxi_read_data(void *priv, char *buf, int maxlen) { struct scpi_vxi *vxi = priv; Device_ReadParms read_parms; Device_ReadResp *read_resp; read_parms.lid = vxi->link; read_parms.io_timeout = VXI_DEFAULT_TIMEOUT; read_parms.lock_timeout = VXI_DEFAULT_TIMEOUT; read_parms.flags = 0; read_parms.termChar = 0; read_parms.requestSize = maxlen; if (!(read_resp = device_read_1(&read_parms, vxi->client)) || read_resp->error) { sr_err("Device read failed for %s with error %d", vxi->address, read_resp->error); return SR_ERR; } memcpy(buf, read_resp->data.data_val, read_resp->data.data_len); vxi->read_complete = read_resp->reason & (RRR_SIZE | RRR_TERM | RRR_END); return read_resp->data.data_len; /* actual number of bytes received */ } static int scpi_vxi_read_complete(void *priv) { struct scpi_vxi *vxi = priv; return vxi->read_complete; } static int scpi_vxi_close(void *priv) { struct scpi_vxi *vxi = priv; Device_Error *dev_error; if (!vxi->client) return SR_ERR; if (!(dev_error = destroy_link_1(&vxi->link, vxi->client))) { sr_err("Link destruction failed for %s", vxi->address); return SR_ERR; } clnt_destroy(vxi->client); vxi->client = NULL; return SR_OK; } static void scpi_vxi_free(void *priv) { struct scpi_vxi *vxi = priv; g_free(vxi->address); g_free(vxi->instrument); } SR_PRIV const struct sr_scpi_dev_inst scpi_vxi_dev = { .name = "VXI", .prefix = "vxi", .priv_size = sizeof(struct scpi_vxi), .dev_inst_new = scpi_vxi_dev_inst_new, .open = scpi_vxi_open, .source_add = scpi_vxi_source_add, .source_remove = scpi_vxi_source_remove, .send = scpi_vxi_send, .read_begin = scpi_vxi_read_begin, .read_data = scpi_vxi_read_data, .read_complete = scpi_vxi_read_complete, .close = scpi_vxi_close, .free = scpi_vxi_free, }; libsigrok-0.3.0/hardware/common/ezusb.c0000644000175000017500000000667412332246667015031 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2010-2012 Bert Vermeulen * * 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 . */ /* * Helper functions for the Cypress EZ-USB / FX2 series chips. */ #include #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "ezusb" SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear) { int ret; unsigned char buf[1]; sr_info("setting CPU reset mode %s...", set_clear ? "on" : "off"); buf[0] = set_clear ? 1 : 0; ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR, 0xa0, 0xe600, 0x0000, buf, 1, 100); if (ret < 0) sr_err("Unable to send control request: %s.", libusb_error_name(ret)); return ret; } SR_PRIV int ezusb_install_firmware(libusb_device_handle *hdl, const char *filename) { FILE *fw; int offset, chunksize, ret, result; unsigned char buf[4096]; sr_info("Uploading firmware at %s", filename); if ((fw = g_fopen(filename, "rb")) == NULL) { sr_err("Unable to open firmware file %s for reading: %s", filename, strerror(errno)); return SR_ERR; } result = SR_OK; offset = 0; while (1) { chunksize = fread(buf, 1, 4096, fw); if (chunksize == 0) break; ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, 0xa0, offset, 0x0000, buf, chunksize, 100); if (ret < 0) { sr_err("Unable to send firmware to device: %s.", libusb_error_name(ret)); result = SR_ERR; break; } sr_info("Uploaded %d bytes", chunksize); offset += chunksize; } fclose(fw); sr_info("Firmware upload done"); return result; } SR_PRIV int ezusb_upload_firmware(libusb_device *dev, int configuration, const char *filename) { struct libusb_device_handle *hdl; int ret; sr_info("uploading firmware to device on %d.%d", libusb_get_bus_number(dev), libusb_get_device_address(dev)); if ((ret = libusb_open(dev, &hdl)) < 0) { sr_err("failed to open device: %s.", libusb_error_name(ret)); return SR_ERR; } /* * The libusbx darwin backend is broken: it can report a kernel driver being * active, but detaching it always returns an error. */ #if !defined(__APPLE__) if (libusb_kernel_driver_active(hdl, 0) == 1) { if ((ret = libusb_detach_kernel_driver(hdl, 0)) < 0) { sr_err("failed to detach kernel driver: %s", libusb_error_name(ret)); return SR_ERR; } } #endif if ((ret = libusb_set_configuration(hdl, configuration)) < 0) { sr_err("Unable to set configuration: %s", libusb_error_name(ret)); return SR_ERR; } if ((ezusb_reset(hdl, 1)) < 0) return SR_ERR; if (ezusb_install_firmware(hdl, filename) < 0) return SR_ERR; if ((ezusb_reset(hdl, 0)) < 0) return SR_ERR; libusb_close(hdl); return SR_OK; } libsigrok-0.3.0/hardware/common/serial.c0000644000175000017500000005451212332246667015152 00000000000000/* * This file is part of the libsigrok project. * * Copyright (C) 2010-2012 Bert Vermeulen * Copyright (C) 2010-2012 Uwe Hermann * Copyright (C) 2012 Alexandru Gagniuc * * 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 . */ #include #include #include #include #include #include "libsigrok.h" #include "libsigrok-internal.h" #define LOG_PREFIX "serial" /** * Open the specified serial port. * * @param serial Previously initialized serial port structure. * @param flags Flags to use when opening the serial port. Possible flags * include SERIAL_RDWR, SERIAL_RDONLY, SERIAL_NONBLOCK. * * If the serial structure contains a serialcomm string, it will be * passed to serial_set_paramstr() after the port is opened. * * @return SR_OK on success, SR_ERR on failure. */ SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags) { int ret; char *error; int sp_flags = 0; if (!serial) { sr_dbg("Invalid serial port."); return SR_ERR; } sr_spew("Opening serial port '%s' (flags %d).", serial->port, flags); sp_get_port_by_name(serial->port, &serial->data); if (flags & SERIAL_RDWR) sp_flags = (SP_MODE_READ | SP_MODE_WRITE); else if (flags & SERIAL_RDONLY) sp_flags = SP_MODE_READ; serial->nonblocking = (flags & SERIAL_NONBLOCK) ? 1 : 0; ret = sp_open(serial->data, sp_flags); switch (ret) { case SP_ERR_ARG: sr_err("Attempt to open serial port with invalid parameters."); return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); sr_err("Error opening port (%d): %s.", sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } if (serial->serialcomm) return serial_set_paramstr(serial, serial->serialcomm); else return SR_OK; } /** * Close the specified serial port. * * @param serial Previously initialized serial port structure. * * @return SR_OK on success, SR_ERR on failure. */ SR_PRIV int serial_close(struct sr_serial_dev_inst *serial) { int ret; char *error; if (!serial) { sr_dbg("Invalid serial port."); return SR_ERR; } if (!serial->data) { sr_dbg("Cannot close unopened serial port %s.", serial->port); return SR_ERR; } sr_spew("Closing serial port %s.", serial->port); ret = sp_close(serial->data); switch (ret) { case SP_ERR_ARG: sr_err("Attempt to close an invalid serial port."); return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); sr_err("Error closing port (%d): %s.", sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } sp_free_port(serial->data); serial->data = NULL; return SR_OK; } /** * Flush serial port buffers. * * @param serial Previously initialized serial port structure. * * @return SR_OK on success, SR_ERR on failure. */ SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial) { int ret; char *error; if (!serial) { sr_dbg("Invalid serial port."); return SR_ERR; } if (!serial->data) { sr_dbg("Cannot flush unopened serial port %s.", serial->port); return SR_ERR; } sr_spew("Flushing serial port %s.", serial->port); ret = sp_flush(serial->data, SP_BUF_BOTH); switch (ret) { case SP_ERR_ARG: sr_err("Attempt to flush an invalid serial port."); return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); sr_err("Error flushing port (%d): %s.", sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } return SR_OK; } static int _serial_write(struct sr_serial_dev_inst *serial, const void *buf, size_t count, int nonblocking) { ssize_t ret; char *error; if (!serial) { sr_dbg("Invalid serial port."); return SR_ERR; } if (!serial->data) { sr_dbg("Cannot use unopened serial port %s.", serial->port); return SR_ERR; } if (nonblocking) ret = sp_nonblocking_write(serial->data, buf, count); else ret = sp_blocking_write(serial->data, buf, count, 0); switch (ret) { case SP_ERR_ARG: sr_err("Attempted serial port write with invalid arguments."); return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); sr_err("Write error (%d): %s.", sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } sr_spew("Wrote %d/%d bytes.", ret, count); return ret; } /** * Write a number of bytes to the specified serial port. * * @param serial Previously initialized serial port structure. * @param buf Buffer containing the bytes to write. * @param count Number of bytes to write. * * @return The number of bytes written, or a negative error code upon failure. */ SR_PRIV int serial_write(struct sr_serial_dev_inst *serial, const void *buf, size_t count) { return _serial_write(serial, buf, count, serial->nonblocking); } SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial, const void *buf, size_t count) { return _serial_write(serial, buf, count, 0); } SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial, const void *buf, size_t count) { return _serial_write(serial, buf, count, 1); } static int _serial_read(struct sr_serial_dev_inst *serial, void *buf, size_t count, int nonblocking) { ssize_t ret; char *error; if (!serial) { sr_dbg("Invalid serial port."); return SR_ERR; } if (!serial->data) { sr_dbg("Cannot use unopened serial port %s.", serial->port); return SR_ERR; } if (nonblocking) ret = sp_nonblocking_read(serial->data, buf, count); else ret = sp_blocking_read(serial->data, buf, count, 0); switch (ret) { case SP_ERR_ARG: sr_err("Attempted serial port read with invalid arguments."); return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); sr_err("Read error (%d): %s.", sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } if (ret > 0) sr_spew("Read %d/%d bytes.", ret, count); return ret; } /** * Read a number of bytes from the specified serial port. * * @param serial Previously initialized serial port structure. * @param buf Buffer where to store the bytes that are read. * @param count The number of bytes to read. * * @return The number of bytes read, or a negative error code upon failure. */ SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf, size_t count) { return _serial_read(serial, buf, count, serial->nonblocking); } SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf, size_t count) { return _serial_read(serial, buf, count, 0); } SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf, size_t count) { return _serial_read(serial, buf, count, 1); } /** * Set serial parameters for the specified serial port. * * @param serial Previously initialized serial port structure. * @param[in] baudrate The baudrate to set. * @param[in] bits The number of data bits to use (5, 6, 7 or 8). * @param[in] parity The parity setting to use (0 = none, 1 = even, 2 = odd). * @param[in] stopbits The number of stop bits to use (1 or 2). * @param[in] flowcontrol The flow control settings to use (0 = none, * 1 = RTS/CTS, 2 = XON/XOFF). * @param[in] rts Status of RTS line (0 or 1; required by some interfaces). * @param[in] dtr Status of DTR line (0 or 1; required by some interfaces). * * @retval SR_OK Success * @retval SR_ERR Failure. */ SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate, int bits, int parity, int stopbits, int flowcontrol, int rts, int dtr) { int ret; char *error; struct sp_port_config *config; if (!serial) { sr_dbg("Invalid serial port."); return SR_ERR; } if (!serial->data) { sr_dbg("Cannot configure unopened serial port %s.", serial->port); return SR_ERR; } sr_spew("Setting serial parameters on port %s.", serial->port); sp_new_config(&config); sp_set_config_baudrate(config, baudrate); sp_set_config_bits(config, bits); switch (parity) { case 0: sp_set_config_parity(config, SP_PARITY_NONE); break; case 1: sp_set_config_parity(config, SP_PARITY_EVEN); break; case 2: sp_set_config_parity(config, SP_PARITY_ODD); break; default: return SR_ERR_ARG; } sp_set_config_stopbits(config, stopbits); sp_set_config_rts(config, flowcontrol == 1 ? SP_RTS_FLOW_CONTROL : rts); sp_set_config_cts(config, flowcontrol == 1 ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE); sp_set_config_dtr(config, dtr); sp_set_config_dsr(config, SP_DSR_IGNORE); sp_set_config_xon_xoff(config, flowcontrol == 2 ? SP_XONXOFF_INOUT : SP_XONXOFF_DISABLED); ret = sp_set_config(serial->data, config); sp_free_config(config); switch (ret) { case SP_ERR_ARG: sr_err("Invalid arguments for setting serial port parameters."); return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); sr_err("Error setting serial port parameters (%d): %s.", sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } return SR_OK; } /** * Set serial parameters for the specified serial port from parameter string. * * @param serial Previously initialized serial port structure. * @param[in] paramstr A serial communication parameters string of the form * "/{/