/** * @brief Convert raw data (from the driver) to double-typed samples * * @param[in] chan Channel descriptor * @param[in] rng Range descriptor * @param[out] dst Ouput buffer * @param[in] src Input buffer * @param[in] cnt Count of conversion to perform * * @return the count of conversion performed, otherwise a negative * error code: * * - -EINVAL is returned if some argument is missing or wrong; * chan, rng and the pointers should be checked; check also the * kernel log ("dmesg"); WARNING: a4l_fill_desc() should be called * before using a4l_rawtod() * */ int a4l_rawtod(a4l_chinfo_t * chan, a4l_rnginfo_t * rng, double *dst, void *src, int cnt) { int size, i = 0, j = 0; lsampl_t tmp; /* Temporary values used for conversion (phys = a * src + b) */ double a, b; /* Temporary data accessor */ lsampl_t(*datax_get) (void *); /* Basic checking */ if (rng == NULL || chan == NULL) return -EINVAL; /* Find out the size in memory */ size = a4l_sizeof_chan(chan); /* Get the suitable accessor */ switch (a4l_sizeof_chan(chan)) { case 4: datax_get = data32_get; break; case 2: datax_get = data16_get; break; case 1: datax_get = data8_get; break; default: return -EINVAL; }; /* Computes the translation factor and the constant only once */ a = ((double)(rng->max - rng->min)) / (((1ULL << chan->nb_bits) - 1) * A4L_RNG_FACTOR); b = ((double)rng->min) / A4L_RNG_FACTOR; while (j < cnt) { /* Properly retrieve the data */ tmp = datax_get(src + i); /* Perform the conversion */ dst[j] = a * tmp + b; /* Update the counters */ i += size; j++; } return j; }
static int dump_text(a4l_desc_t *dsc, unsigned char *buf, int size) { int err = 0, width, tmp_size = 0; char *fmt; a4l_chinfo_t *chan; /* Retrieve the subdevice data size */ err = a4l_get_chinfo(dsc, idx_subd, idx_chan, &chan); if (err < 0) { fprintf(stderr, "insn_read: info for channel %d " "on subdevice %d not available (err=%d)\n", idx_chan, idx_subd, err); goto out; } width = a4l_sizeof_chan(chan); if (width < 0) { fprintf(stderr, "insn_read: incoherent info for channel %d\n", idx_chan); err = width; goto out; } switch(width) { case 1: fmt = "0x%02x\n"; break; case 2: fmt = "0x%04x\n"; break; case 4: default: fmt = "0x%08x\n"; break; } while (size - tmp_size > 0) { unsigned long values[64]; int i, tmp_cnt = ((size - tmp_size) / width > 64) ? 64 : ((size - tmp_size) / width); err = a4l_rawtoul(chan, values, buf + tmp_size, tmp_cnt); if (err < 0) goto out; for (i = 0; i < tmp_cnt; i++) fprintf(stdout, fmt, values[i]); tmp_size += tmp_cnt * width; } out: return err; }
static int dump_converted(a4l_desc_t *dsc, unsigned char *buf, int size) { int err = 0, width, tmp_size = 0; a4l_chinfo_t *chan; a4l_rnginfo_t *rng; /* Retrieve the channel info */ err = a4l_get_chinfo(dsc, idx_subd, idx_chan, &chan); if (err < 0) { fprintf(stderr, "insn_read: info for channel %d " "on subdevice %d not available (err=%d)\n", idx_chan, idx_subd, err); goto out; } /* Retrieve the range info */ err = a4l_get_rnginfo(dsc, idx_subd, idx_chan, idx_rng, &rng); if (err < 0) { fprintf(stderr, "insn_read: failed to recover range descriptor\n"); goto out; } width = a4l_sizeof_chan(chan); if (width < 0) { fprintf(stderr, "insn_read: incoherent info for channel %d\n", idx_chan); err = width; goto out; } fprintf(stdout, "Non Calibrated values: \n"); while (size - tmp_size > 0) { double values[64]; int i, tmp_cnt = ((size - tmp_size) / width > 64) ? 64 : ((size - tmp_size) / width); err = a4l_rawtod(chan, rng, values, buf + tmp_size, tmp_cnt); if (err < 0) goto out; for (i = 0; i < tmp_cnt; i++) { fprintf(stdout, "%F\n", values[i]); } tmp_size += tmp_cnt * width; } out: return err; }
/** * @brief Convert double-typed samples to raw data (for the driver) * * @param[in] chan Channel descriptor * @param[in] rng Range descriptor * @param[out] dst Ouput buffer * @param[in] src Input buffer * @param[in] cnt Count of conversion to perform * * @return the count of conversion performed, otherwise a negative * error code: * * - -EINVAL is returned if some argument is missing or wrong; * chan, rng and the pointers should be checked; check also the * kernel log ("dmesg"); WARNING: a4l_fill_desc() should be called * before using a4l_dtoraw() * */ int a4l_dtoraw(a4l_chinfo_t * chan, a4l_rnginfo_t * rng, void *dst, double *src, int cnt) { int size, i = 0, j = 0; /* Temporary values used for conversion (dst = a * phys - b) */ double a, b; /* Temporary data accessor */ void (*datax_set) (void *, lsampl_t); /* Basic checking */ if (rng == NULL || chan == NULL) return -EINVAL; /* Find out the size in memory */ size = a4l_sizeof_chan(chan); /* Select the suitable accessor */ switch (size) { case 4: datax_set = data32_set; break; case 2: datax_set = data16_set; break; case 1: datax_set = data8_set; break; default: return -EINVAL; }; /* Computes the translation factor and the constant only once */ a = (((double)A4L_RNG_FACTOR) / (rng->max - rng->min)) * ((1ULL << chan->nb_bits) - 1); b = ((double)(rng->min) / (rng->max - rng->min)) * ((1ULL << chan->nb_bits) - 1); while (j < cnt) { /* Performs the conversion */ datax_set(dst + i, (lsampl_t) (a * src[j] - b)); /* Updates the counters */ i += size; j++; } return j; }
/** * @brief Pack unsigned long values into raw data (for the driver) * * This function takes as input a table of unsigned long values and * gather them according to the channel width. It is a convenience * routine which performs no conversion, just formatting. * * @param[in] chan Channel descriptor * @param[in] rng Range descriptor * @param[out] dst Ouput buffer * @param[in] src Input buffer * @param[in] cnt Count of transfer to copy * * @return the count of copy performed, otherwise a negative error * code: * * - -EINVAL is returned if some argument is missing or wrong; * chan, rng and the pointers should be checked; check also the * kernel log ("dmesg"); WARNING: a4l_fill_desc() should be called * before using a4l_ultoraw() * */ int a4l_ultoraw(a4l_chinfo_t * chan, void *dst, unsigned long *src, int cnt) { int size, i = 0, j = 0; /* Temporary data accessor */ void (*datax_set) (void *, lsampl_t); /* Basic checking */ if (chan == NULL) return -EINVAL; /* Find out the size in memory */ size = a4l_sizeof_chan(chan); /* Select the suitable accessor */ switch (size) { case 4: datax_set = data32_set; break; case 2: datax_set = data16_set; break; case 1: datax_set = data8_set; break; default: return -EINVAL; }; while (j < cnt) { /* Perform the copy */ datax_set(dst + i, (lsampl_t)src[j]); /* Update the counters */ i += size; j++; } return j; }
/** * @brief Unpack raw data (from the driver) into unsigned long values * * This function takes as input driver-specific data and scatters each * element into an entry of an unsigned long table. It is a * convenience routine which performs no conversion, just copy. * * @param[in] chan Channel descriptor * @param[in] rng Range descriptor * @param[out] dst Ouput buffer * @param[in] src Input buffer * @param[in] cnt Count of transfer to copy * * @return the count of copy performed, otherwise a negative error * code: * * - -EINVAL is returned if some argument is missing or wrong; * chan, rng and the pointers should be checked; check also the * kernel log ("dmesg"); WARNING: a4l_fill_desc() should be called * before using a4l_ultoraw() * */ int a4l_rawtoul(a4l_chinfo_t * chan, unsigned long *dst, void *src, int cnt) { int size, i = 0, j = 0; /* Temporary data accessor */ lsampl_t(*datax_get) (void *); /* Basic checking */ if (chan == NULL) return -EINVAL; /* Find out the size in memory */ size = a4l_sizeof_chan(chan); /* Get the suitable accessor */ switch (size) { case 4: datax_get = data32_get; break; case 2: datax_get = data16_get; break; case 1: datax_get = data8_get; break; default: return -EINVAL; }; while (j < cnt) { /* Properly copy the data */ dst[j] = (unsigned long)datax_get(src + i); /* Update the counters */ i += size; j++; } return j; }
int main(int argc, char *argv[]) { int ret = 0, len, ofs; unsigned int i, scan_size = 0, cnt = 0; unsigned long buf_size; void *map = NULL; a4l_desc_t dsc = { .sbdata = NULL }; int (*dump_function) (a4l_desc_t *, a4l_cmd_t*, unsigned char *, int) = dump_text; /* Compute arguments */ while ((ret = getopt_long(argc, argv, "vrd:s:S:c:mwk:h", cmd_read_opts, NULL)) >= 0) { switch (ret) { case 'v': verbose = 1; break; case 'r': real_time = 1; break; case 'd': filename = optarg; break; case 's': cmd.idx_subd = strtoul(optarg, NULL, 0); break; case 'S': cmd.stop_arg = strtoul(optarg, NULL, 0); break; case 'c': str_chans = optarg; break; case 'm': use_mmap = 1; break; case 'w': dump_function = dump_raw; break; case 'k': wake_count = strtoul(optarg, NULL, 0); break; case 'h': default: do_print_usage(); return 0; } } if (isatty(STDOUT_FILENO) && dump_function == dump_raw) { fprintf(stderr, "cmd_read: cannot dump raw data on a terminal\n\n"); return -EINVAL; } /* Recover the channels to compute */ do { cmd.nb_chan++; len = strlen(str_chans); ofs = strcspn(str_chans, ","); if (sscanf(str_chans, "%u", &chans[cmd.nb_chan - 1]) == 0) { fprintf(stderr, "cmd_read: bad channel argument\n"); return -EINVAL; } str_chans += ofs + 1; } while (len != ofs); /* Update the command structure */ cmd.scan_end_arg = cmd.nb_chan; cmd.stop_src = cmd.stop_arg != 0 ? TRIG_COUNT : TRIG_NONE; if (real_time != 0) { if (verbose != 0) printf("cmd_read: switching to real-time mode\n"); /* Prevent any memory-swapping for this program */ ret = mlockall(MCL_CURRENT | MCL_FUTURE); if (ret < 0) { ret = errno; fprintf(stderr, "cmd_read: mlockall failed (ret=%d)\n", ret); goto out_main; } /* Turn the current process into an RT task */ ret = rt_task_shadow(&rt_task_desc, NULL, 1, 0); if (ret < 0) { fprintf(stderr, "cmd_read: rt_task_shadow failed (ret=%d)\n", ret); goto out_main; } } /* Open the device */ ret = a4l_open(&dsc, filename); if (ret < 0) { fprintf(stderr, "cmd_read: a4l_open %s failed (ret=%d)\n", filename, ret); return ret; } if (verbose != 0) { printf("cmd_read: device %s opened (fd=%d)\n", filename, dsc.fd); printf("cmd_read: basic descriptor retrieved\n"); printf("\t subdevices count = %d\n", dsc.nb_subd); printf("\t read subdevice index = %d\n", dsc.idx_read_subd); printf("\t write subdevice index = %d\n", dsc.idx_write_subd); } /* Allocate a buffer so as to get more info (subd, chan, rng) */ dsc.sbdata = malloc(dsc.sbsize); if (dsc.sbdata == NULL) { fprintf(stderr, "cmd_read: malloc failed \n"); return -ENOMEM; } /* Get this data */ ret = a4l_fill_desc(&dsc); if (ret < 0) { fprintf(stderr, "cmd_read: a4l_fill_desc failed (ret=%d)\n", ret); goto out_main; } if (verbose != 0) printf("cmd_read: complex descriptor retrieved\n"); /* Get the size of a single acquisition */ for (i = 0; i < cmd.nb_chan; i++) { a4l_chinfo_t *info; ret = a4l_get_chinfo(&dsc, cmd.idx_subd, cmd.chan_descs[i], &info); if (ret < 0) { fprintf(stderr, "cmd_read: a4l_get_chinfo failed (ret=%d)\n", ret); goto out_main; } if (verbose != 0) { printf("cmd_read: channel %x\n", cmd.chan_descs[i]); printf("\t ranges count = %d\n", info->nb_rng); printf("\t bit width = %d (bits)\n", info->nb_bits); } scan_size += a4l_sizeof_chan(info); } if (verbose != 0) { printf("cmd_read: scan size = %u\n", scan_size); if (cmd.stop_arg != 0) printf("cmd_read: size to read = %u\n", scan_size * cmd.stop_arg); } /* Cancel any former command which might be in progress */ a4l_snd_cancel(&dsc, cmd.idx_subd); if (use_mmap != 0) { /* Get the buffer size to map */ ret = a4l_get_bufsize(&dsc, cmd.idx_subd, &buf_size); if (ret < 0) { fprintf(stderr, "cmd_read: a4l_get_bufsize() failed (ret=%d)\n", ret); goto out_main; } if (verbose != 0) printf("cmd_read: buffer size = %lu bytes\n", buf_size); /* Map the analog input subdevice buffer */ ret = a4l_mmap(&dsc, cmd.idx_subd, buf_size, &map); if (ret < 0) { fprintf(stderr, "cmd_read: a4l_mmap() failed (ret=%d)\n", ret); goto out_main; } if (verbose != 0) printf ("cmd_read: mmap performed successfully (map=0x%p)\n", map); } ret = a4l_set_wakesize(&dsc, wake_count); if (ret < 0) { fprintf(stderr, "cmd_read: a4l_set_wakesize failed (ret=%d)\n", ret); goto out_main; } if (verbose != 0) printf("cmd_read: wake size successfully set (%lu)\n", wake_count); /* Send the command to the input device */ ret = a4l_snd_command(&dsc, &cmd); if (ret < 0) { fprintf(stderr, "cmd_read: a4l_snd_command failed (ret=%d)\n", ret); goto out_main; } if (verbose != 0) printf("cmd_read: command successfully sent\n"); if (use_mmap == 0) { /* Fetch data */ do { /* Perform the read operation */ ret = a4l_async_read(&dsc, buf, BUF_SIZE, A4L_INFINITE); if (ret < 0) { fprintf(stderr, "cmd_read: a4l_read failed (ret=%d)\n", ret); goto out_main; } /* Display the results */ if (dump_function(&dsc, &cmd, buf, ret) < 0) { ret = -EIO; goto out_main; } /* Update the counter */ cnt += ret; } while (ret > 0); } else { unsigned long front = 0; /* Fetch data without any memcpy */ do { /* Retrieve and update the buffer's state (In input case, we recover how many bytes are available to read) */ ret = a4l_mark_bufrw(&dsc, cmd.idx_subd, front, &front); if (ret == -ENOENT) break; else if (ret < 0) { fprintf(stderr, "cmd_read: a4l_mark_bufrw() failed (ret=%d)\n", ret); goto out_main; } /* If there is nothing to read, wait for an event (Note that a4l_poll() also retrieves the data amount to read; in our case it is useless as we have to update the data read counter) */ if (front == 0) { ret = a4l_poll(&dsc, cmd.idx_subd, A4L_INFINITE); if (ret == 0) break; else if (ret < 0) { fprintf(stderr, "cmd_read: a4l_poll() failed (ret=%d)\n", ret); goto out_main; } } /* Display the results */ if (dump_function(&dsc, &cmd, &((unsigned char *)map)[cnt % buf_size], front) < 0) { ret = -EIO; goto out_main; } /* Update the counter */ cnt += front; } while (1); } if (verbose != 0) printf("cmd_read: %d bytes successfully received\n", cnt); ret = 0; out_main: if (use_mmap != 0) /* Clean the pages table */ munmap(map, buf_size); /* Free the buffer used as device descriptor */ if (dsc.sbdata != NULL) free(dsc.sbdata); /* Release the file descriptor */ a4l_close(&dsc); return ret; }
int dump_text(a4l_desc_t *dsc, a4l_cmd_t *cmd, unsigned char *buf, int size) { static int cur_chan; int i, err = 0, tmp_size = 0; char *fmts[MAX_NB_CHAN]; a4l_chinfo_t *chans[MAX_NB_CHAN]; for (i = 0; i < cmd->nb_chan; i++) { int width; err = a4l_get_chinfo(dsc, cmd->idx_subd, cmd->chan_descs[i], &chans[i]); if (err < 0) { fprintf(stderr, "cmd_read: a4l_get_chinfo failed (ret=%d)\n", err); goto out; } width = a4l_sizeof_chan(chans[i]); if (width < 0) { fprintf(stderr, "cmd_read: incoherent info for channel %d\n", cmd->chan_descs[i]); err = width; goto out; } switch(width) { case 1: fmts[i] = "0x%02x "; break; case 2: fmts[i] = "0x%04x "; break; case 4: default: fmts[i] = "0x%08x "; break; } } while (tmp_size < size) { unsigned long value; err = a4l_rawtoul(chans[cur_chan], &value, buf + tmp_size, 1); if (err < 0) goto out; fprintf(stdout, fmts[cur_chan], value); /* We assume a4l_sizeof_chan() cannot return because we already called it on the very same channel descriptor */ tmp_size += a4l_sizeof_chan(chans[cur_chan]); if(++cur_chan == cmd->nb_chan) { fprintf(stdout, "\n"); cur_chan = 0; } } fflush(stdout); out: return err; }
int main(int argc, char *argv[]) { int err = 0; unsigned int cnt = 0; a4l_desc_t dsc = { .sbdata = NULL }; a4l_sbinfo_t *sbinfo; a4l_chinfo_t *chinfo; a4l_rnginfo_t *rnginfo; int (*dump_function) (a4l_desc_t *, unsigned char *, int) = dump_text; /* Compute arguments */ while ((err = getopt_long(argc, argv, "vrd:s:S:c:R:y:wh", insn_read_opts, NULL)) >= 0) { switch (err) { case 'v': verbose = 1; break; case 'd': filename = optarg; break; case 's': idx_subd = strtoul(optarg, NULL, 0); break; case 'S': scan_size = strtoul(optarg, NULL, 0); break; case 'c': idx_chan = strtoul(optarg, NULL, 0); break; case 'R': idx_rng = strtoul(optarg, NULL, 0); dump_function = dump_converted; break; case 'w': dump_function = dump_raw; break; case 'y': dump_function = dump_calibrated; calibration_file = optarg; break; case 'h': default: do_print_usage(); return 0; } } if (isatty(STDOUT_FILENO) && dump_function == dump_raw) { fprintf(stderr, "insn_read: cannot dump raw data on a terminal\n\n"); return -EINVAL; } /* Open the device */ err = a4l_open(&dsc, filename); if (err < 0) { fprintf(stderr, "insn_read: a4l_open %s failed (err=%d)\n", filename, err); return err; } if (verbose != 0) { printf("insn_read: device %s opened (fd=%d)\n", filename, dsc.fd); printf("insn_read: basic descriptor retrieved\n"); printf("\t subdevices count = %d\n", dsc.nb_subd); printf("\t read subdevice index = %d\n", dsc.idx_read_subd); printf("\t write subdevice index = %d\n", dsc.idx_write_subd); } /* Allocate a buffer so as to get more info (subd, chan, rng) */ dsc.sbdata = malloc(dsc.sbsize); if (dsc.sbdata == NULL) { err = -ENOMEM; fprintf(stderr, "insn_read: info buffer allocation failed\n"); goto out_insn_read; } /* Get this data */ err = a4l_fill_desc(&dsc); if (err < 0) { fprintf(stderr, "insn_read: a4l_fill_desc failed (err=%d)\n", err); goto out_insn_read; } if (verbose != 0) printf("insn_read: complex descriptor retrieved\n"); /* If no subdevice index was set, look for an analog input subdevice */ if (idx_subd == -1) idx_subd = dsc.idx_read_subd; if (idx_subd == -1) { fprintf(stderr, "insn_read: no analog input subdevice available\n"); err = -EINVAL; goto out_insn_read; } if (verbose != 0) printf("insn_read: selected subdevice index = %d\n", idx_subd); /* We must check that the subdevice is really an AI one (in case, the subdevice index was set with the option -s) */ err = a4l_get_subdinfo(&dsc, idx_subd, &sbinfo); if (err < 0) { fprintf(stderr, "insn_read: get_sbinfo(%d) failed (err = %d)\n", idx_subd, err); err = -EINVAL; goto out_insn_read; } if ((sbinfo->flags & A4L_SUBD_TYPES) != A4L_SUBD_AI) { fprintf(stderr, "insn_read: wrong subdevice selected " "(not an analog input)\n"); err = -EINVAL; goto out_insn_read; } if (idx_rng >= 0) { err = a4l_get_rnginfo(&dsc, idx_subd, idx_chan, idx_rng, &rnginfo); if (err < 0) { fprintf(stderr, "insn_read: failed to recover range descriptor\n"); goto out_insn_read; } if (verbose != 0) { printf("insn_read: range descriptor retrieved\n"); printf("\t min = %ld\n", rnginfo->min); printf("\t max = %ld\n", rnginfo->max); } } /* Retrieve the subdevice data size */ err = a4l_get_chinfo(&dsc, idx_subd, idx_chan, &chinfo); if (err < 0) { fprintf(stderr, "insn_read: info for channel %d on subdevice %d not available (err=%d)\n", idx_chan, idx_subd, err); goto out_insn_read; } /* Set the data size to read */ scan_size *= a4l_sizeof_chan(chinfo); if (verbose != 0) { printf("insn_read: channel width is %u bits\n", chinfo->nb_bits); printf("insn_read: global scan size is %u\n", scan_size); } while (cnt < scan_size) { int tmp = (scan_size - cnt) < BUF_SIZE ? (scan_size - cnt) : BUF_SIZE; /* Perform the synchronous read */ err = a4l_sync_read(&dsc, idx_subd, CHAN(idx_chan), 0, buf, tmp); if (err < 0) { fprintf(stderr, "insn_read: a4l_sync_read failed (err=%d)\n", err); goto out_insn_read; } /* Dump the read data */ tmp = dump_function(&dsc, buf, err); if (tmp < 0) { err = tmp; goto out_insn_read; } /* Update the count */ cnt += err; } if (verbose != 0) printf("insn_read: %u bytes successfully received\n", cnt); err = 0; out_insn_read: /* Free the information buffer */ if (dsc.sbdata != NULL) free(dsc.sbdata); /* Release the file descriptor */ a4l_close(&dsc); return err; }
static int dump_calibrated(a4l_desc_t *dsc, unsigned char *buf, int size) { struct a4l_calibration_data cal_info; struct a4l_polynomial converter; int err = 0, width, tmp_size = 0; a4l_chinfo_t *chan; a4l_rnginfo_t *rng; /* Retrieve the channel info */ err = a4l_get_chinfo(dsc, idx_subd, idx_chan, &chan); if (err < 0) { fprintf(stderr, "insn_read: info for channel %d " "on subdevice %d not available (err=%d)\n", idx_chan, idx_subd, err); goto out; } /* Retrieve the range info */ err = a4l_get_rnginfo(dsc, idx_subd, idx_chan, idx_rng, &rng); if (err < 0) { fprintf(stderr, "insn_read: failed to recover range descriptor\n"); goto out; } width = a4l_sizeof_chan(chan); if (width < 0) { fprintf(stderr, "insn_read: incoherent info for channel %d\n", idx_chan); err = width; goto out; } err = a4l_read_calibration_file(calibration_file, &cal_info); if (err < 0) { fprintf(stderr, "insn_read: error reading the calibration file \n"); goto out; } err = a4l_get_softcal_converter(&converter, idx_subd, idx_chan, idx_rng, &cal_info); if (err < 0) { fprintf(stderr, "insn_read: failed to get the softcal converter \n"); goto out; } fprintf(stdout, "Calibrated values: \n"); while (size - tmp_size > 0) { double values[64]; int i, tmp_cnt = ((size - tmp_size) / width > 64) ? 64 : ((size - tmp_size) / width); err = a4l_rawtodcal(chan, values, buf + tmp_size, tmp_cnt, &converter); if (err < 0) goto out; for (i = 0; i < tmp_cnt; i++) fprintf(stdout, "%F\n", values[i]); tmp_size += tmp_cnt * width; } out: return err; }