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; }
/*!***************************************************************************** ******************************************************************************* \note dio32_NI6259_write_cmd_buffer \date Jan. 2011 \remarks Uses the cmd structure to write a command buffer to the DIO device at very high communication rate. This function with the abort statement at the end is still experimental and is not really used so far. ******************************************************************************* Function Parameters: [in]=input,[out]=output \param[in] buf : the command buffer \param[in] n_buf: number of elements to write ******************************************************************************/ int dio32_NI6259_write_cmd_buffer(int *buf, int n_buf) { int i,j,rc; static unsigned long buf_size; unsigned long buf_left; static int *map = NULL; static int firsttime = TRUE; unsigned int chans[32]={ 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}; a4l_cmd_t cmd = { .idx_subd = SUBDEV_DIO, .flags = 0, .start_src = TRIG_INT, // internal trigger .start_arg = 0, .scan_begin_src = TRIG_EXT, .scan_begin_arg = NI_CDIO_SCAN_BEGIN_SRC_G0_OUT, // channel used to trigger the scans .convert_src = TRIG_NOW, .convert_arg = 0, /* in ns */ .scan_end_src = TRIG_COUNT, .scan_end_arg = 32, .stop_src = TRIG_NONE, .stop_arg = 0, .nb_chan = 32, .chan_descs = chans, }; a4l_insn_t insn = { .type = A4L_INSN_INTTRIG, .idx_subd = SUBDEV_DIO, .data_size = 0, }; if (firsttime) { firsttime = FALSE; // map the communication buffer to user space // Get the buffer size to map rc = a4l_get_bufsize(&desc, SUBDEV_DIO, &buf_size); if (rc < 0) { printf("a4l_get_bufsize() failed (rc=%d)\n",rc); return FALSE; } // Map the subdevice buffer rc = a4l_mmap(&desc, SUBDEV_DIO, buf_size, (void *)&map); if (rc < 0) { printf("a4l_mmap() failed (rc=%d)\n",rc); return FALSE; } } // configure device in write mode rc = dio32_NI6259_config(ajcDATAMASK | ajcCTRLMASK,DIO_WRITE); if (rc < 0) { printf("write_cmd_buffer: dio32_NI6259_config failed (ret=%d)\n", rc); return FALSE; } // send the command rc = a4l_snd_command(&desc, &cmd); if (rc < 0) { printf("write_cmd_buffer: a4l_snd_command failed (ret=%d)\n", rc); return FALSE; } // write buf to the map buffer for (i=1; i<=n_buf; ++i) map[i-1] = buf[i]; // tell the device the size of the data rc = a4l_mark_bufrw(&desc, SUBDEV_DIO, n_buf*sizeof(int), &buf_left); if (rc < 0) { printf("a4l_mark_bufrw() failed (rc=%d)\n",rc); return FALSE; } // trigger the communication rc = a4l_snd_insn(&desc, &insn); if (rc < 0) printf("ni_test: triggering failed (rc=%d)\n",rc); // check whether the device is busy and wait int count_busy = 0; const int max_count_busy = 1000; while ((rc = a4l_poll(&desc, SUBDEV_DIO, A4L_INFINITE)) > 0) { // wait for completion if (++count_busy > max_count_busy) { printf("write_cmd_buffer: dio32_NI6259_config too many (%d) EBUSY timeouts\n", max_count_busy); return FALSE; } taskDelay(10000); } if (rc < 0 && rc!= -EPIPE) { printf("a4l_poll() failed (rc=%d)\n",rc); return FALSE; } return TRUE; } /*!***************************************************************************** ******************************************************************************* \note dio16_NI6259_read \date Feb 2010 \remarks reads from PFI device a 16 bit value with bit mask ******************************************************************************* Function Parameters: [in]=input,[out]=output \param[in] mask : which bits to read \param[out] val : the value read ******************************************************************************/ inline int dio16_NI6259_read(int mask, int *val) { int i; int rc; // configure the device to read mode for (i=0; i<16; ++i) { if ( ((1 << i) & mask) > 0) { if (dio16_channel_mode[i] != DIO_READ) { rc = a4l_config_subd(&desc,SUBDEV_PFI,A4L_INSN_CONFIG_DIO_INPUT,i); if (rc < 0) { printf("dio16_NI6259_read: failed to configure DIO (rc=%d, channel %d)\n",rc,i); return FALSE; } dio16_channel_mode[i] = DIO_READ; } } } // read the value rc = a4l_sync_dio(&desc, SUBDEV_PFI, &mask, val); if (rc < 0) { printf("dio16_NI6259_read: failed to communicate to DIO (rc=%d)\n",rc); return FALSE; } *val = (*val) & mask; return TRUE; } /*!***************************************************************************** ******************************************************************************* \note dio16_NI6259_write \date Feb 2010 \remarks writes to DIO device a 16 bit value with bit mask ******************************************************************************* Function Parameters: [in]=input,[out]=output \param[in] mask : which bits to write \param[in] val : the value to write ******************************************************************************/ inline int dio16_NI6259_write(int mask, int val) { int i; int rc; // configure the device channels to read mode if needed for (i=0; i<16; ++i) { if ( ((1 << i) & mask) > 0) { if (dio16_channel_mode[i] != DIO_WRITE) { rc = a4l_config_subd(&desc,SUBDEV_PFI,A4L_INSN_CONFIG_DIO_OUTPUT,i); if (rc < 0) { printf("dio16_NI6259_write: failed to configure DIO (rc=%d, channel %d)\n",rc,i); return FALSE; } dio16_channel_mode[i] = DIO_WRITE; } } } // write the value rc = a4l_sync_dio(&desc, SUBDEV_PFI, &mask, &val); if (rc < 0) { printf("dio16_NI6259_write: failed to communicate to DIO (rc=%d)\n",rc); return FALSE; } return TRUE; }