| /******************************************************************************* |
| Copyright (C) Marvell International Ltd. and its affiliates |
| |
| This software file (the "File") is owned and distributed by Marvell |
| International Ltd. and/or its affiliates ("Marvell") under the following |
| alternative licensing terms. Once you have made an election to distribute the |
| File under one of the following license alternatives, please (i) delete this |
| introductory statement regarding license alternatives, (ii) delete the two |
| license alternatives that you have not elected to use and (iii) preserve the |
| Marvell copyright notice above. |
| |
| ******************************************************************************** |
| Marvell Commercial License Option |
| |
| If you received this File from Marvell and you have entered into a commercial |
| license agreement (a "Commercial License") with Marvell, the File is licensed |
| to you under the terms of the applicable Commercial License. |
| |
| ******************************************************************************** |
| Marvell GPL License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File in accordance with the terms and conditions of the General |
| Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| available along with the File in the license.txt file or by writing to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| |
| THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| DISCLAIMED. The GPL License provides additional details about this warranty |
| disclaimer. |
| ******************************************************************************** |
| Marvell BSD License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File under the following licensing terms. |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| * Redistributions of source code must retain the above copyright notice, |
| this list of conditions and the following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| * Neither the name of Marvell nor the names of its contributors may be |
| used to endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| *******************************************************************************/ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <sys/ioctl.h> |
| #include <string.h> |
| |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| #include <sys/mman.h> |
| |
| |
| #include "mv_tsu_ioctl.h" |
| |
| |
| /* |
| Usage: |
| TsuTool <device> <read/write> <file> <options> |
| */ |
| |
| |
| #define BUFSIZE 2048 |
| #define TIMESTAMP_SIZE 4 |
| #define TSU_TOOL_STAMP 0x4D52564C |
| #define FILE_HDR_SIZE 64 |
| |
| #define READ 1 |
| #define WRITE 0 |
| |
| char *util_name; |
| char *data_buff = NULL; |
| |
| int g_is_read = -1; |
| struct tsu_buff_info g_buff_info; |
| int g_raw_mode = 0; |
| int g_b2b_mode = 0; |
| int g_auto_ts_mode = 0; |
| int retry_on_fail = 0; |
| int g_data_blk_sz = 0; // Actual block size <= g_buf_size |
| int g_buf_size =0; // Buffer size |
| unsigned int g_frequency = -1; |
| FILE *g_stat_fd = NULL; |
| int g_ts_data_size = 0; |
| int g_tms_data_size = 0; |
| |
| void data_read(int dev_fd, FILE *file_fd); |
| void data_write(int dev_fd, FILE *file_fd); |
| int get_buff_info(int dev_fd); |
| |
| void usage(void) |
| { |
| fprintf(stderr,"Usage: %s <device> <r/w> <file> <options>\n",util_name); |
| fprintf(stderr,"<file> can be set to stdout.\n"); |
| fprintf(stderr,"Where <options> are:\n"); |
| fprintf(stderr,"-r <tms file>: Write / Read data in raw TS format.\n" |
| " <tms file> is the file that holds / will hold the timestamp information.\n"); |
| fprintf(stderr,"-f <freq>: The frequency at which data is to be received / transmitted.\n" |
| " In Rx mode, this is mandatory.\n" |
| " In Tx mode, this will override the file header frequency.\n"); |
| fprintf(stderr,"-b: Transmit the TS file in Back-to-Back mode, no timestamps are needed.\n"); |
| fprintf(stderr,"-a: Enable automatic timestamp mode, timestamps are generated by TS driver.\n"); |
| exit(1); |
| } |
| |
| /* |
| * Helper function for printing the TSU statistics. |
| */ |
| void tsu_print_stat(struct tsu_stat *stat) |
| { |
| fprintf(stderr,"\tTS Interface Error Interrupts: %d.\n",stat->ts_if_err); |
| fprintf(stderr,"\tTS Fifo Overflow Interrupts: %d.\n",stat->fifo_ovfl); |
| fprintf(stderr,"\tTS Clock Sync Expired Interrupts: %d.\n",stat->clk_sync_exp); |
| fprintf(stderr,"\tTS Connection Error Interrupts: %d.\n",stat->ts_conn_err); |
| fprintf(stderr,"\n"); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| char *dev_name; |
| char *file_name; |
| int dev_fd = 0; |
| FILE *file_fd = NULL; |
| int cnt = 0; |
| struct tsu_stat tsu_stat; |
| |
| /* Eecutable name. */ |
| util_name = argv[cnt++]; |
| |
| if(argc < 4) { |
| if(argc > 1) |
| fprintf(stderr,"Missing parameters.\n"); |
| usage(); |
| } |
| |
| /* Device name */ |
| dev_name = argv[cnt++]; |
| |
| /* Read / Write operation. */ |
| if(!strcmp(argv[cnt],"r")) { |
| g_is_read = 1; |
| } else if(!strcmp(argv[cnt],"w")) { |
| g_is_read = 0; |
| } else { |
| fprintf(stderr,"Bad read / write option.\n"); |
| usage(); |
| } |
| cnt++; |
| |
| /* Open the device. */ |
| if(g_is_read) |
| dev_fd = open(dev_name, O_RDONLY); |
| else |
| dev_fd = open(dev_name, O_WRONLY); |
| |
| if(dev_fd <= 0) { |
| fprintf(stderr,"%s - Cannot open device %s.\n",util_name,dev_name); |
| exit(2); |
| } |
| |
| /* Input / Output file name. */ |
| file_name = argv[cnt++]; |
| if(g_is_read) { |
| if(!strncmp(file_name,"stdout",strlen("stdout"))) |
| file_fd = stdout; |
| else |
| file_fd = fopen(file_name, "w+"); |
| }else{ |
| file_fd = fopen(file_name, "r"); |
| } |
| if(file_fd == NULL) { |
| fprintf(stderr,"%s - Cannot open file %s.\n",util_name,file_name); |
| goto error; |
| } |
| |
| if(get_buff_info(dev_fd) < 0){ |
| fprintf(stderr,"%s - Failed to retrieve device buffer configuration.\n"); |
| goto error; |
| } |
| |
| /* Allocate buffer. */ |
| data_buff = malloc(g_buf_size); |
| if(data_buff == NULL) { |
| fprintf(stderr,"%s - Failed to allocate memory (%d Bytes).\n",util_name, |
| BUFSIZE); |
| goto error; |
| } |
| |
| if(process_options(argc,argv,cnt,dev_fd) < 0) { |
| fprintf(stderr,"Bad options.\n"); |
| goto error; |
| } |
| |
| /* Clear statistics. */ |
| if(ioctl(dev_fd,MVTSU_IOCCLEARSTAT,0) < 0) { |
| fprintf(stderr,"Error Clearing statistics.\n"); |
| goto error; |
| } |
| |
| if(g_is_read) |
| data_read(dev_fd,file_fd); |
| else |
| data_write(dev_fd,file_fd); |
| |
| /* Print statistics. */ |
| if(ioctl(dev_fd,MVTSU_IOCGETSTAT,&tsu_stat) < 0) { |
| fprintf(stderr,"Error Printing statistics.\n"); |
| goto error; |
| } |
| tsu_print_stat(&tsu_stat); |
| |
| error: |
| if(dev_fd != 0) |
| close(dev_fd); |
| if(file_fd != NULL) |
| fclose(file_fd); |
| if(data_buff != NULL) |
| free(data_buff); |
| if(g_stat_fd != NULL) |
| fclose(g_stat_fd); |
| return 0; |
| } |
| |
| |
| int check_write_file_device_params(struct tsu_buff_info *buff_info) |
| { |
| if(!g_raw_mode) { |
| /* buffer configuration for input data & TSU must match.*/ |
| if(buff_info->aggr_mode == g_buff_info.aggr_mode) { |
| if((g_buff_info.aggr_mode == aggrMode1) && |
| (g_buff_info.aggr_num_packets != |
| buff_info->aggr_num_packets)) { |
| fprintf(stderr,"Mismtach in Num of Aggregation packets (%d, %d).\n", |
| g_buff_info.aggr_num_packets, |
| buff_info->aggr_num_packets); |
| return -1; |
| } |
| if((g_buff_info.aggr_mode == aggrMode2) && |
| (g_buff_info.aggr_mode2_tmstmp_off != |
| buff_info->aggr_mode2_tmstmp_off)) { |
| fprintf(stderr,"Mismtach in Aggregation Timestamp offset (%d, %d).\n", |
| g_buff_info.aggr_mode2_tmstmp_off, |
| buff_info->aggr_mode2_tmstmp_off); |
| return -1; |
| } |
| } |
| |
| if(buff_info->aggr_mode != g_buff_info.aggr_mode) { |
| if(g_buff_info.aggr_mode == aggrMode1){ |
| fprintf(stderr,"Device configured in aggregation mode 1 while file is not.\n"); |
| return -1; |
| } |
| if(buff_info->aggr_mode == aggrMode1) { |
| fprintf(stderr,"File configured in aggregation mode 1 while port is not.\n"); |
| return -1; |
| } |
| /* File @ mode2, Device @ Aggr-Disabled. */ |
| if((buff_info->aggr_mode == aggrMode2) && |
| (buff_info->aggr_mode2_tmstmp_off != TIMESTAMP_SIZE)) { |
| fprintf(stderr,"File is in aggr-mode-2 mode with timestamp " |
| "offset != 4, and device is at aggr-dis mode.\n"); |
| return -1; |
| } |
| |
| /* Device @ mode2, File @ Aggr-Disabled. */ |
| if((g_buff_info.aggr_mode == aggrMode2) && |
| (g_buff_info.aggr_mode2_tmstmp_off != TIMESTAMP_SIZE)) { |
| fprintf(stderr,"Device is in aggr-mode-2 mode with timestamp " |
| "offset != 4, and file is at aggr-dis mode.\n"); |
| return -1; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| |
| int single_read_write(int is_read, int fd, char *buf, int count) |
| { |
| int tmp = 0; |
| int ret; |
| |
| while(tmp < count) { |
| |
| if(is_read) { |
| ret = read(fd,buf + tmp,count - tmp); |
| } else { |
| ret = write(fd,buf + tmp,count - tmp); |
| } |
| |
| if(ret <= 0) |
| return ret; |
| tmp += ret; |
| } |
| return count; |
| } |
| |
| |
| int single_fread_fwrite(int is_read, FILE *fd, char *buf, int count) |
| { |
| int tmp = 0; |
| int ret; |
| |
| while(tmp < count) { |
| |
| if(is_read) { |
| ret = fread(buf + tmp,1,count - tmp,fd); |
| } else { |
| ret = fwrite(buf + tmp,1,count - tmp,fd); |
| } |
| |
| if(ret <= 0) |
| return ret; |
| tmp += ret; |
| } |
| return count; |
| } |
| |
| |
| void setup_buffer_timestamps(char *buff, int *s_offs, int *init_tms,int *new_size) |
| { |
| int i; |
| int total_diffs = 0; |
| int first_tms = -1; |
| int tmp; |
| |
| memcpy(&first_tms,buff,TIMESTAMP_SIZE); |
| *init_tms = first_tms; |
| |
| if(g_buff_info.aggr_mode == aggrMode1) { |
| /* Calculate the timestamp interval. */ |
| memcpy(&tmp, |
| buff + ((g_buff_info.aggr_num_packets - 1) * TIMESTAMP_SIZE), |
| TIMESTAMP_SIZE); |
| total_diffs = tmp - first_tms; |
| total_diffs = total_diffs / (g_buff_info.aggr_num_packets - 1); |
| |
| /* Copy timestamp interval */ |
| memcpy(buff + (g_buff_info.aggr_num_packets - 2) * TIMESTAMP_SIZE, |
| &total_diffs,TIMESTAMP_SIZE); |
| |
| /* Copy initial timestamp */ |
| memcpy(buff + (g_buff_info.aggr_num_packets - 1) * TIMESTAMP_SIZE, |
| &first_tms,TIMESTAMP_SIZE); |
| |
| *s_offs = (g_buff_info.aggr_num_packets - 2) * TIMESTAMP_SIZE; |
| *new_size -= (*s_offs); |
| } else { |
| *s_offs = 0; |
| } |
| return; |
| } |
| |
| |
| void data_write(int dev_fd, FILE *file_fd) |
| { |
| int cnt; |
| FILE *fd; |
| int tmp; |
| int s_offs, e_offs; |
| int pkt_size; |
| int first_write = 1; |
| struct tsu_buff_info buff_info; |
| int init_tms; |
| unsigned int freq; |
| |
| if(!g_b2b_mode && !g_auto_ts_mode) { |
| /* Read TS info from file header. */ |
| /* pktsize mode aggr_pkts_num tmstmp_offset */ |
| if(!g_raw_mode) |
| fd = file_fd; |
| else |
| fd = g_stat_fd; |
| |
| if(fread(data_buff,1,FILE_HDR_SIZE,fd) < FILE_HDR_SIZE) { |
| fprintf(stderr,"Failed to read file information header.\n"); |
| return; |
| } |
| |
| sscanf(data_buff,"%d %d %d %d %d %d",&tmp,&pkt_size,&buff_info.aggr_mode, |
| &buff_info.aggr_num_packets,&buff_info.aggr_mode2_tmstmp_off, |
| &freq); |
| if(tmp != TSU_TOOL_STAMP) { |
| fprintf(stderr,"Bad stamp at file header (0x%x).\n",tmp); |
| return; |
| } |
| |
| /* If user did not specify a frequency for TX, take the file frequency. */ |
| if(g_frequency == -1) |
| g_frequency = freq; |
| |
| if(pkt_size != g_buff_info.pkt_size) { |
| fprintf(stderr,"File Packet size (%d) & TSU packet size (%d) do not match.\n", |
| pkt_size,g_buff_info.pkt_size); |
| return; |
| } |
| |
| if(check_write_file_device_params(&buff_info) < 0) |
| return; |
| } |
| |
| /* Calculate the values of g_ts_data_size & g_tms_data_size. */ |
| if(g_raw_mode) { |
| if(g_buff_info.aggr_mode == aggrMode1) { |
| g_ts_data_size = |
| (g_buff_info.pkt_size * |
| g_buff_info.aggr_num_packets); |
| g_tms_data_size = (TIMESTAMP_SIZE * |
| g_buff_info.aggr_num_packets); |
| } |
| else if(g_buff_info.aggr_mode == aggrMode2) { |
| g_ts_data_size = g_buff_info.pkt_size; |
| g_tms_data_size = TIMESTAMP_SIZE; |
| } |
| else { /* Aggregation disabled. */ |
| g_ts_data_size = g_buff_info.pkt_size; |
| g_tms_data_size = TIMESTAMP_SIZE; |
| } |
| } else { |
| g_ts_data_size = g_data_blk_sz; |
| g_tms_data_size = 0; |
| } |
| |
| /* Setup Tx frequency. */ |
| if(ioctl(dev_fd,MVTSU_IOCFREQSET,&g_frequency) < 0) { |
| fprintf(stderr,"Error configuring port frequency.\n"); |
| goto done; |
| } |
| #if 0 |
| printf("g_ts_data_size = %d, g_data_blk_sz = %d.\n", |
| g_ts_data_size,g_tms_data_size); |
| #endif |
| while(1) { |
| cnt = 0; |
| s_offs = 0; |
| e_offs = 0; |
| while(cnt < g_data_blk_sz) { |
| // printf("cnt = %d, ",cnt); |
| if(g_tms_data_size) { |
| if(g_buff_info.aggr_mode == aggrMode2) { |
| e_offs += (g_buff_info.aggr_mode2_tmstmp_off - |
| g_tms_data_size); |
| cnt += (g_buff_info.aggr_mode2_tmstmp_off - |
| g_tms_data_size); |
| } |
| // printf("sread %d, ",g_tms_data_size); |
| tmp = single_fread_fwrite(READ,g_stat_fd,data_buff + e_offs, |
| g_tms_data_size); |
| if(tmp != g_tms_data_size) { |
| fprintf(stderr,"Error reading from timestamp file.\n"); |
| goto done; |
| } |
| e_offs += tmp; |
| cnt += tmp; |
| } |
| |
| // printf("dread %d, ",g_ts_data_size); |
| tmp = single_fread_fwrite(READ,file_fd,data_buff + e_offs, |
| g_ts_data_size); |
| if(tmp < 0) { |
| fprintf(stderr,"Error reading from source file.\n"); |
| goto done; |
| } |
| if(tmp == 0) { |
| /* No more input. */ |
| goto done; |
| } |
| e_offs += tmp; |
| cnt += tmp; |
| setup_buffer_timestamps(data_buff,&s_offs,&init_tms,&cnt); |
| } |
| |
| if(first_write) { |
| struct tsu_tmstmp_info tms_info; |
| tms_info.enable_tms = !g_b2b_mode; |
| tms_info.timestamp = init_tms; |
| if(ioctl(dev_fd,MVTSU_IOCTXTMSSET,&tms_info) < 0) { |
| fprintf(stderr,"Cannot set initial timestamp for TX operation.\n"); |
| goto done; |
| } |
| first_write = 0; |
| } |
| |
| // printf("twrite %d.\n",g_data_blk_sz); |
| cnt = single_read_write(WRITE,dev_fd,data_buff + s_offs, |
| g_data_blk_sz); |
| if(cnt <= 0) { |
| fprintf(stderr,"Error writing to target device.\n"); |
| break; |
| } |
| } |
| |
| done: |
| /* tell device that tx is over. */ |
| if(ioctl(dev_fd,MVTSU_IOCTXDONE,0) < 0) { |
| fprintf(stderr,"Error in TX-Done IOCTL.\n"); |
| return; |
| } |
| return; |
| } |
| |
| void data_read(int dev_fd, FILE *file_fd) |
| { |
| int cnt = 0; |
| int tmp; |
| int offs = 0; |
| int drop = 10; |
| |
| /* Write TS info the file header. */ |
| /* pktsize mode aggr_pkts_num tmstmp_offset */ |
| sprintf(data_buff,"%d %d %d %d %d %d", |
| TSU_TOOL_STAMP,g_buff_info.pkt_size,g_buff_info.aggr_mode, |
| g_buff_info.aggr_num_packets, |
| g_buff_info.aggr_mode2_tmstmp_off, g_frequency); |
| tmp = strlen(data_buff); |
| while(tmp < FILE_HDR_SIZE) |
| data_buff[tmp++] = ' '; |
| data_buff[tmp] = '\0'; |
| |
| if(!g_raw_mode) |
| cnt = fwrite(data_buff,1,strlen(data_buff),file_fd); |
| else |
| cnt = fwrite(data_buff,1,strlen(data_buff),g_stat_fd); |
| |
| if(cnt != strlen(data_buff)) { |
| fprintf(stderr,"Error wrting file header.\n"); |
| return; |
| } |
| |
| /* Calculate the values of g_ts_data_size & g_tms_data_size. */ |
| if(g_raw_mode) { |
| if(g_buff_info.aggr_mode == aggrMode1) { |
| g_ts_data_size = |
| (g_buff_info.pkt_size * |
| g_buff_info.aggr_num_packets); |
| g_tms_data_size = (TIMESTAMP_SIZE * |
| g_buff_info.aggr_num_packets); |
| } |
| else if(g_buff_info.aggr_mode == aggrMode2) { |
| g_ts_data_size = g_buff_info.pkt_size; |
| g_tms_data_size = g_buff_info.aggr_mode2_tmstmp_off; |
| } |
| else { /* Aggregation disabled. */ |
| g_ts_data_size = g_buff_info.pkt_size; |
| g_tms_data_size = TIMESTAMP_SIZE; |
| } |
| } else { |
| g_ts_data_size = g_data_blk_sz; |
| g_tms_data_size = 0; |
| } |
| |
| /* Setup frequency. */ |
| if(ioctl(dev_fd,MVTSU_IOCFREQSET,&g_frequency) < 0) { |
| fprintf(stderr,"Error configuring port frequency.\n"); |
| goto done; |
| } |
| |
| // fprintf(stderr,"g_raw_mode = %d, g_ts_data_size = %d, g_tms_data_size = %d.\n", |
| // g_raw_mode, g_ts_data_size,g_tms_data_size); |
| cnt = 0; |
| while(1) { |
| |
| if(offs != 0) |
| fprintf(stderr,"offs = %d.\n"); |
| tmp = single_read_write(READ,dev_fd,data_buff + offs, |
| g_data_blk_sz - offs); |
| if(tmp < 0) { |
| fprintf(stderr,"Error reading from source device / file.\n"); |
| break; |
| } |
| if(drop) { |
| drop--; |
| continue; |
| } |
| |
| cnt += tmp; |
| if(cnt == 0) |
| break; |
| while(cnt >= (g_ts_data_size + g_tms_data_size)) { |
| // fprintf(stderr,"cnt - %d, ",cnt); |
| tmp = 0; |
| if(g_tms_data_size > 0) { |
| if(g_buff_info.aggr_mode == aggrMode2) { |
| // fprintf(stderr,"TMSW = %d, ",offs); |
| /* write only the timestamp part. */ |
| tmp = single_fread_fwrite(WRITE,g_stat_fd, |
| data_buff + offs, |
| TIMESTAMP_SIZE); |
| if(tmp < TIMESTAMP_SIZE) { |
| fprintf(stderr,"Error writing to timestamps file.\n"); |
| goto done; |
| } |
| } else { |
| tmp = single_fread_fwrite(WRITE,g_stat_fd, |
| data_buff + offs, |
| g_tms_data_size); |
| if(tmp < g_tms_data_size) { |
| fprintf(stderr,"Error writing to timestamps file.\n"); |
| goto done; |
| } |
| } |
| |
| offs += tmp; |
| } |
| // fprintf(stderr,"TSDW = %d.\n",offs); |
| tmp = single_fread_fwrite(WRITE,file_fd,data_buff + offs, |
| g_ts_data_size); |
| if(tmp < g_ts_data_size) { |
| fprintf(stderr,"Error writing to data file.\n"); |
| goto done; |
| } |
| offs += g_ts_data_size; |
| cnt -= (g_ts_data_size + g_tms_data_size); |
| } |
| |
| if(cnt > 0) { |
| memmove(data_buff,data_buff + offs, cnt); |
| offs = cnt; |
| } |
| else { |
| offs = 0; |
| } |
| } |
| done: |
| return; |
| } |
| |
| |
| int get_buff_info(int dev_fd) |
| { |
| char *tmp; |
| |
| if(ioctl(dev_fd,MVTSU_IOCBUFFPARAMGET,&g_buff_info) < 0){ |
| fprintf(stderr,"Error reading device buffer information.\n"); |
| return -1; |
| } |
| |
| if(g_buff_info.aggr_mode == aggrMode1) { |
| if(g_is_read) |
| g_data_blk_sz = ((g_buff_info.pkt_size + TIMESTAMP_SIZE) * |
| g_buff_info.aggr_num_packets); |
| else |
| g_data_blk_sz = ((g_buff_info.pkt_size * |
| g_buff_info.aggr_num_packets) + |
| (2 * TIMESTAMP_SIZE)); |
| g_buf_size = ((g_buff_info.pkt_size + TIMESTAMP_SIZE) * |
| g_buff_info.aggr_num_packets); |
| tmp = "Mode 1"; |
| } else if(g_buff_info.aggr_mode == aggrMode2) { |
| g_data_blk_sz = ((g_buff_info.pkt_size + |
| g_buff_info.aggr_mode2_tmstmp_off) * |
| g_buff_info.aggr_num_packets); |
| g_buf_size = g_data_blk_sz; |
| tmp = "Mode 2"; |
| } else { |
| g_data_blk_sz = (g_buff_info.pkt_size + TIMESTAMP_SIZE); |
| g_buf_size = g_data_blk_sz; |
| tmp = "Disabled"; |
| } |
| #if 0 |
| fprintf(stderr,"\n"); |
| fprintf(stderr,"\tPacket Size: %d Bytes\n",g_buff_info.pkt_size); |
| fprintf(stderr,"\tAggregation %s\n",tmp); |
| if(g_buff_info.aggr_mode != aggrModeDisabled) |
| fprintf(stderr,"\tAggregation packets: %d.\n",g_buff_info.aggr_num_packets); |
| if(g_buff_info.aggr_mode == aggrMode2) |
| fprintf(stderr,"\tAggregation Timestamp offset: %d.\n", |
| g_buff_info.aggr_mode2_tmstmp_off); |
| #endif |
| // fprintf(stderr,"\tCalculated data buffer size: %d Bytes.\n",g_buf_size); |
| // fprintf(stderr,"\tCalculated data-block size: %d Bytes.\n",g_data_blk_sz); |
| return 0; |
| } |
| |
| |
| int process_options(int argc, char *argv[],int idx,int dev_fd) |
| { |
| char *stat_file = NULL; |
| |
| while(idx < argc) { |
| if(argv[idx][0] != '-') |
| goto error; |
| switch (argv[idx][1]) { |
| case 'r': |
| g_raw_mode = 1; |
| stat_file = argv[idx+1]; |
| idx+=2; |
| break; |
| case 'f': |
| g_frequency = atoi(argv[idx+1]); |
| idx+=2; |
| break; |
| case 'b': |
| g_raw_mode = 1; |
| g_b2b_mode = 1; |
| stat_file = "/dev/zero"; |
| idx += 1; |
| break; |
| case 'a': |
| g_auto_ts_mode = 1; |
| g_raw_mode = 1; |
| stat_file = "/dev/zero"; |
| idx += 1; |
| break; |
| default: |
| goto error; |
| } |
| } |
| |
| if(g_b2b_mode && g_is_read) { |
| fprintf(stderr,"%s - Cannot work in Back-To-Back mode in read direction.", |
| util_name); |
| goto error; |
| } |
| |
| if(g_raw_mode) { |
| if(g_is_read) |
| g_stat_fd = fopen(stat_file, "w+"); |
| else |
| g_stat_fd = fopen(stat_file, "r"); |
| if(g_stat_fd == NULL){ |
| fprintf(stderr,"%s - Cannot open file %s.\n",util_name,stat_file); |
| goto error; |
| } |
| } |
| |
| if(g_is_read || g_auto_ts_mode) { |
| if(g_frequency == -1) { |
| fprintf(stderr, |
| "%s - Must provide data frequency (For Rx & auto timestamp mode).\n",util_name); |
| goto error; |
| } |
| } |
| |
| if(g_auto_ts_mode) { |
| if(ioctl(dev_fd,MVTSU_IOCAUTOTMS,&g_auto_ts_mode) < 0) { |
| fprintf(stderr,"Error enabling auto timestamp mode.\n"); |
| goto error; |
| } |
| } |
| |
| return 0; |
| |
| error: |
| return -1; |
| } |