Index: /branches/libfreebob-1.4/CVSROOT/cvswrappers =================================================================== --- /branches/libfreebob-1.4/CVSROOT/cvswrappers (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/cvswrappers (revision 3) @@ -0,0 +1,19 @@ +# This file affects handling of files based on their names. +# +# The -m option specifies whether CVS attempts to merge files. +# +# The -k option specifies keyword expansion (e.g. -kb for binary). +# +# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers) +# +# wildcard [option value][option value]... +# +# where option is one of +# -f from cvs filter value: path to filter +# -t to cvs filter value: path to filter +# -m update methodology value: MERGE or COPY +# -k expansion mode value: b, o, kkv, &c +# +# and value is a single-quote delimited value. +# For example: +#*.gif -k 'b' Index: /branches/libfreebob-1.4/CVSROOT/checkoutlist =================================================================== --- /branches/libfreebob-1.4/CVSROOT/checkoutlist (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/checkoutlist (revision 3) @@ -0,0 +1,13 @@ +# The "checkoutlist" file is used to support additional version controlled +# administrative files in $CVSROOT/CVSROOT, such as template files. +# +# The first entry on a line is a filename which will be checked out from +# the corresponding RCS file in the $CVSROOT/CVSROOT directory. +# The remainder of the line is an error message to use if the file cannot +# be checked out. +# +# File format: +# +# [][] +# +# comment lines begin with '#' Index: /branches/libfreebob-1.4/CVSROOT/editinfo =================================================================== --- /branches/libfreebob-1.4/CVSROOT/editinfo (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/editinfo (revision 3) @@ -0,0 +1,21 @@ +# The "editinfo" file is used to allow verification of logging +# information. It works best when a template (as specified in the +# rcsinfo file) is provided for the logging procedure. Given a +# template with locations for, a bug-id number, a list of people who +# reviewed the code before it can be checked in, and an external +# process to catalog the differences that were code reviewed, the +# following test can be applied to the code: +# +# Making sure that the entered bug-id number is correct. +# Validating that the code that was reviewed is indeed the code being +# checked in (using the bug-id number or a seperate review +# number to identify this particular code set.). +# +# If any of the above test failed, then the commit would be aborted. +# +# Actions such as mailing a copy of the report to each reviewer are +# better handled by an entry in the loginfo file. +# +# One thing that should be noted is the the ALL keyword is not +# supported. There can be only one entry that matches a given +# repository. Index: /branches/libfreebob-1.4/CVSROOT/rcsinfo =================================================================== --- /branches/libfreebob-1.4/CVSROOT/rcsinfo (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/rcsinfo (revision 3) @@ -0,0 +1,13 @@ +# The "rcsinfo" file is used to control templates with which the editor +# is invoked on commit and import. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being made to, relative to the +# $CVSROOT. For the first match that is found, then the remainder of the +# line is the name of the file that contains the template. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". Index: /branches/libfreebob-1.4/CVSROOT/commitinfo =================================================================== --- /branches/libfreebob-1.4/CVSROOT/commitinfo (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/commitinfo (revision 3) @@ -0,0 +1,15 @@ +# The "commitinfo" file is used to control pre-commit checks. +# The filter on the right is invoked with the repository and a list +# of files to check. A non-zero exit of the filter program will +# cause the commit to be aborted. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being committed to, relative +# to the $CVSROOT. For the first match that is found, then the remainder +# of the line is the name of the filter to run. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". Index: /branches/libfreebob-1.4/CVSROOT/config =================================================================== --- /branches/libfreebob-1.4/CVSROOT/config (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/config (revision 3) @@ -0,0 +1,21 @@ +# Set this to "no" if pserver shouldn't check system users/passwords +#SystemAuth=no + +# Put CVS lock files in this directory rather than directly in the repository. +#LockDir=/var/lock/cvs + +# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top +# level of the new working directory when using the `cvs checkout' +# command. +#TopLevelAdmin=no + +# Set `LogHistory' to `all' or `TOEFWUPCGMAR' to log all transactions to the +# history file, or a subset as needed (ie `TMAR' logs all write operations) +#LogHistory=TOEFWUPCGMAR + +# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg +# script to change the log message. Set it to `stat' to force CVS to verify# that the file has changed before reading it (this can take up to an extra +# second per directory being committed, so it is not recommended for large +# repositories. Set it to `never' (the previous CVS behavior) to prevent +# verifymsg scripts from changing the log message. +#RereadLogAfterVerify=always Index: /branches/libfreebob-1.4/CVSROOT/taginfo =================================================================== --- /branches/libfreebob-1.4/CVSROOT/taginfo (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/taginfo (revision 3) @@ -0,0 +1,20 @@ +# The "taginfo" file is used to control pre-tag checks. +# The filter on the right is invoked with the following arguments: +# +# $1 -- tagname +# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d +# $3 -- repository +# $4-> file revision [file revision ...] +# +# A non-zero exit of the filter program will cause the tag to be aborted. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being committed to, relative +# to the $CVSROOT. For the first match that is found, then the remainder +# of the line is the name of the filter to run. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". Index: /branches/libfreebob-1.4/CVSROOT/modules =================================================================== --- /branches/libfreebob-1.4/CVSROOT/modules (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/modules (revision 3) @@ -0,0 +1,26 @@ +# Three different line formats are valid: +# key -a aliases... +# key [options] directory +# key [options] directory files... +# +# Where "options" are composed of: +# -i prog Run "prog" on "cvs commit" from top-level of module. +# -o prog Run "prog" on "cvs checkout" of module. +# -e prog Run "prog" on "cvs export" of module. +# -t prog Run "prog" on "cvs rtag" of module. +# -u prog Run "prog" on "cvs update" of module. +# -d dir Place module in directory "dir" instead of module name. +# -l Top-level directory only -- do not recurse. +# +# NOTE: If you change any of the "Run" options above, you'll have to +# release and re-checkout any working directories of these modules. +# +# And "directory" is a path to a directory relative to $CVSROOT. +# +# The "-a" option specifies an alias. An alias is interpreted as if +# everything on the right of the "-a" had been typed on the command line. +# +# You can encode a module within a module by using the special '&' +# character to interpose another module into the current module. This +# can be useful for creating a module that consists of many directories +# spread out over the entire source repository. Index: /branches/libfreebob-1.4/CVSROOT/notify =================================================================== --- /branches/libfreebob-1.4/CVSROOT/notify (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/notify (revision 3) @@ -0,0 +1,12 @@ +# The "notify" file controls where notifications from watches set by +# "cvs watch add" or "cvs edit" are sent. The first entry on a line is +# a regular expression which is tested against the directory that the +# change is being made to, relative to the $CVSROOT. If it matches, +# then the remainder of the line is a filter program that should contain +# one occurrence of %s for the user to notify, and information on its +# standard input. +# +# "ALL" or "DEFAULT" can be used in place of the regular expression. +# +# For example: +#ALL mail -s "CVS notification" %s Index: /branches/libfreebob-1.4/CVSROOT/verifymsg =================================================================== --- /branches/libfreebob-1.4/CVSROOT/verifymsg (revision 3) +++ /branches/libfreebob-1.4/CVSROOT/verifymsg (revision 3) @@ -0,0 +1,21 @@ +# The "verifymsg" file is used to allow verification of logging +# information. It works best when a template (as specified in the +# rcsinfo file) is provided for the logging procedure. Given a +# template with locations for, a bug-id number, a list of people who +# reviewed the code before it can be checked in, and an external +# process to catalog the differences that were code reviewed, the +# following test can be applied to the code: +# +# Making sure that the entered bug-id number is correct. +# Validating that the code that was reviewed is indeed the code being +# checked in (using the bug-id number or a seperate review +# number to identify this particular code set.). +# +# If any of the above test failed, then the commit would be aborted. +# +# Actions such as mailing a copy of the report to each reviewer are +# better handled by an entry in the loginfo file. +# +# One thing that should be noted is the the ALL keyword is not +# supported. There can be only one entry that matches a given +# repository. Index: /branches/libfreebob-1.4/CVSROOT/loginfo =================================================================== --- /branches/libfreebob-1.4/CVSROOT/loginfo (revision 7) +++ /branches/libfreebob-1.4/CVSROOT/loginfo (revision 7) @@ -0,0 +1,30 @@ +# The "loginfo" file controls where "cvs commit" log information +# is sent. The first entry on a line is a regular expression which must match +# the directory that the change is being made to, relative to the +# $CVSROOT. If a match is found, then the remainder of the line is a filter +# program that should expect log information on its standard input. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name ALL appears as a regular expression it is always used +# in addition to the first matching regex or DEFAULT. +# +# You may specify a format string as part of the +# filter. The string is composed of a `%' followed +# by a single format character, or followed by a set of format +# characters surrounded by `{' and `}' as separators. The format +# characters are: +# +# s = file name +# V = old version number (pre-checkin) +# v = new version number (post-checkin) +# t = tag or branch name +# +# For example: +#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog +# or +#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog +CVSROOT /cvsroot/sitedocs/CVSROOT/cvstools/syncmail %{sVv} wagi@users.sourceforge.net + +DEFAULT /cvsroot/sitedocs/CVSROOT/cvstools/syncmail %{sVv} freebob-cvs@lists.sourceforge.net Index: /branches/libfreebob-1.4/freebob/tests/get-xml-description.c =================================================================== --- /branches/libfreebob-1.4/freebob/tests/get-xml-description.c (revision 117) +++ /branches/libfreebob-1.4/freebob/tests/get-xml-description.c (revision 117) @@ -0,0 +1,131 @@ +// get-xml-description.c +// +/**************************************************************************** + Test program to get the XML description from freebob + + Copyright (C) 2005, Pieter Palmers. All rights reserved. + + + Freebob = FireWire Audio for Linux... + http://freebob.sf.net + +*****************************************************************************/ +#include +#include +#include +#include +#include +#include + +void freebobctl_ipc_error(int num, const char *m, const char *path) { + fprintf(stderr,"liblo server error %d in path %s: %s\n", num, path, m); +}; + +int freebobctl_ipc_response_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { + + char **buffer=(char **)user_data; + if(buffer) { + if((argc>0) && (types[0]=='s')) { + *buffer=(char *)strdup(&argv[0]->s); + } else { + *buffer=NULL; + } + } + + return 0; + +} + +int freebobctl_ipc_generic_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { + +/* int i; + + fprintf(stderr,"message received on path: <%s>\n", path); + for (i=0; i +#include +#include + +typedef struct { + unsigned char m_cts : 4; + unsigned char m_ctype : 4; + unsigned char m_subunit_type : 5; + unsigned char m_subunit_ID : 3; +} FCP_Header; + +typedef struct { + FCP_Header m_header; + unsigned char m_command; + unsigned char m_subfunction; + unsigned char m_destination_plugs; + unsigned char m_source_plugs; + unsigned char m_dummy[2]; +} FCP_Command_PlugInfo; + +typedef union { + FCP_Command_PlugInfo m_command; + unsigned int m_sel[2]; +} UFCP_Command_PlugInfo; + +int +main( int argc, char** argv ) +{ + quadlet_t request; + request = AVC1394_CTYPE_STATUS + | AVC1394_SUBUNIT_TYPE_UNIT + | AVC1394_SUBUNIT_ID_IGNORE + | AVC1394_COMMAND_PLUG_INFO + | 0x00; + + printf( "request:\t0x%08x\n", request ); + + UFCP_Command_PlugInfo fcpCPlugInfo; + fcpCPlugInfo.m_sel[0] = 0; + fcpCPlugInfo.m_sel[1] = 0; + + fcpCPlugInfo.m_command.m_header.m_cts = 0x00; + fcpCPlugInfo.m_command.m_header.m_ctype = 0x01; + fcpCPlugInfo.m_command.m_header.m_subunit_type = 0x1f; + fcpCPlugInfo.m_command.m_header.m_subunit_ID = 0x07; + + fcpCPlugInfo.m_command.m_command = 0x2; + + printf( "FCP PlugInfo (be):\t0x%08x\n",fcpCPlugInfo.m_sel[0] ); + printf( "FCP PlugInfo (le):\t0x%08x\n", ntohl(fcpCPlugInfo.m_sel[0]) ); + + return 0; +} + +/* + * Local variables: + * compile-command: "gcc -Wall -g -std=c99 -o byte_order byte_order.c -I/usr/local/includ -L/usr/local/lib -lavc1394 -lrom1394 -lraw1394" + * End: + */ Index: /branches/libfreebob-1.4/freebob/tests/detect_avc_unit.c =================================================================== --- /branches/libfreebob-1.4/freebob/tests/detect_avc_unit.c (revision 43) +++ /branches/libfreebob-1.4/freebob/tests/detect_avc_unit.c (revision 43) @@ -0,0 +1,287 @@ +/* detect_avc_unit.c + * Copyright (C) 2004,05 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* XXX: add those to avc1394.h */ +#define AVC1394_SUBUNIT_TYPE_AUDIO (1 <<19) +#define AVC1394_SUBUNIT_TYPE_PRINTER (2 <<19) +#define AVC1394_SUBUNIT_TYPE_CA (6 <<19) +#define AVC1394_SUBUNIT_TYPE_PANEL (9 <<19) +#define AVC1394_SUBUNIT_TYPE_BULLETIN_BOARD (0xA <<19) +#define AVC1394_SUBUNIT_TYPE_CAMERA_STORAGE (0xB <<19) + +void +print_rom_directory (raw1394handle_t handle, + rom1394_directory* rom_dir, + int node_id) +{ + int length; + octlet_t guid; + + rom1394_bus_options bus_options; + + printf ( "\nNode %d: \n", node_id); + printf ( "-------------------------------------------------\n"); + length = rom1394_get_bus_info_block_length (handle, node_id); + printf ("bus info block length = %d\n", length); + printf ("bus id = 0x%08x\n", rom1394_get_bus_id(handle, node_id)); + rom1394_get_bus_options (handle, node_id, &bus_options); + printf ("bus options:\n"); + printf (" isochronous resource manager capable: %d\n", bus_options.irmc); + printf (" cycle master capable : %d\n", bus_options.cmc); + printf (" isochronous capable : %d\n", bus_options.isc); + printf (" bus manager capable : %d\n", bus_options.bmc); + printf (" cycle master clock accuracy : %d ppm\n", bus_options.cyc_clk_acc); + printf (" maximum asynchronous record size : %d bytes\n", bus_options.max_rec); + guid = rom1394_get_guid (handle, node_id); + printf ("GUID: 0x%08x%08x\n", (quadlet_t) (guid>>32), + (quadlet_t) (guid & 0xffffffff)); + rom1394_get_directory ( handle, node_id, rom_dir); + printf ("directory:\n"); + printf (" node capabilities : 0x%08x\n", rom_dir->node_capabilities); + printf (" vendor id : 0x%08x\n", rom_dir->vendor_id); + printf (" unit spec id : 0x%08x\n", rom_dir->unit_spec_id); + printf (" unit software version: 0x%08x\n", rom_dir->unit_sw_version); + printf (" model id : 0x%08x\n", rom_dir->model_id); + printf (" textual leaves : %s\n", rom_dir->label); + + return; +} + +/* used for debug output */ +char* +decode_response(quadlet_t response) +{ + quadlet_t resp = AVC1394_MASK_RESPONSE(response); + if (resp == AVC1394_RESPONSE_NOT_IMPLEMENTED) + return "NOT IMPLEMENTED"; + if (resp == AVC1394_RESPONSE_ACCEPTED) + return "ACCEPTED"; + if (resp == AVC1394_RESPONSE_REJECTED) + return "REJECTED"; + if (resp == AVC1394_RESPONSE_IN_TRANSITION) + return "IN TRANSITION"; + if (resp == AVC1394_RESPONSE_IMPLEMENTED) + return "IMPLEMENTED / STABLE"; + if (resp == AVC1394_RESPONSE_CHANGED) + return "CHANGED"; + if (resp == AVC1394_RESPONSE_INTERIM) + return "INTERIM"; + return "huh?"; +} + +void +print_avc_unit_info (raw1394handle_t handle, int node_id) +{ + printf ("node %d AVC video monitor? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_VIDEO_MONITOR) ? + "yes":"no"); + printf ("node %d AVC audio? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_AUDIO) ? + "yes":"no"); + printf ("node %d AVC printer? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_PRINTER) ? + "yes":"no"); + printf ("node %d AVC disk recorder? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_DISC_RECORDER) ? + "yes":"no"); + printf ("node %d AVC video recorder? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_TAPE_RECORDER) ? + "yes":"no"); + printf ("node %d AVC vcr? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_VCR) ? + "yes":"no"); + printf ("node %d AVC tuner? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_TUNER) ? + "yes":"no"); + printf ("node %d AVC CA? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_CA) ? + "yes":"no"); + printf ("node %d AVC video camera? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_VIDEO_CAMERA) ? + "yes":"no"); + printf ("node %d AVC panel? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_PANEL) ? + "yes":"no"); + printf ("node %d AVC camera storage? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_CAMERA_STORAGE) ? + "yes":"no"); + printf ("node %d AVC bulletin board? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_BULLETIN_BOARD) ? + "yes":"no"); + printf ("node %d AVC vendor specificr? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_VENDOR_UNIQUE) ? + "yes":"no"); + printf ("node %d AVC extended? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_EXTENDED) ? + "yes":"no"); + printf ("node %d AVC unit? %s\n", node_id, + avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_UNIT) ? + "yes":"no"); + return; +} + +void +plug_discovery (raw1394handle_t handle, int node_id) +{ + quadlet_t request[2]; + quadlet_t* response; + + printf ("Plug discovery:\n"); + +#define REQUEST (AVC1394_CTYPE_STATUS | AVC1394_SUBUNIT_TYPE_UNIT | AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_PLUG_INFO) + + request[0] = REQUEST; + request[1] = 0xffffffff; + + printf("Request quadlet: 0x%08x\n", request[0]); + + response = avc1394_transaction_block (handle, node_id, request, 2, 1); + + if ( response == NULL ) + { + fprintf (stderr, "Could not read plug info.\n"); + return; + } + + puts(decode_response(response[0])); + +#undef AVC1394_GET_OPERAND +#define AVC1394_GET_OPERAND(x, n) (((x) & (0xFF000000 >> ((((n)-1)%4)*8))) >> (((4-(n))%4)*8)) + + printf (" Response quadlet: 0x%08x\n", response[1]); + + printf (" Serial_Bus_input_plugs: %u\n", + AVC1394_GET_OPERAND(response[1], 1)); + printf (" Serial_Bus_output_plugs: %u\n", + AVC1394_GET_OPERAND(response[1], 2)); + printf (" External_input_plugs: %u\n", + AVC1394_GET_OPERAND(response[1], 3)); + printf (" External_output_plugs: %u\n", + AVC1394_GET_OPERAND(response[1], 4)); + + return; +} + +int +main(int argc, char **argv) +{ + rom1394_directory rom_dir; + raw1394handle_t handle; + + handle = raw1394_new_handle (); + if (handle == NULL) + { + if (!errno) + { + fprintf (stderr, "lib1394raw not compatable.\n"); + } + else + { + perror ("Could not get 1394 handle"); + fprintf (stderr, "Is ieee1394, driver, and raw1394 loaded?\n"); + } + exit(1); + } + + if (raw1394_set_port(handle, 0) < 0) + { + perror ("Could not set port"); + raw1394_destroy_handle (handle); + exit(1); + } + + for (int node_id = 0; node_id < raw1394_get_nodecount (handle); ++node_id) + { + if (rom1394_get_directory (handle, node_id, &rom_dir) < 0) + { + fprintf (stderr, "Error reading config rom directory for node %d\n", + node_id); + raw1394_destroy_handle (handle); + exit(1); + } + + print_rom_directory (handle, &rom_dir, node_id); + + switch (rom1394_get_node_type (&rom_dir)) + { + case ROM1394_NODE_TYPE_UNKNOWN: + printf ("Node %d has node type UNKNOWN\n", node_id); + break; + case ROM1394_NODE_TYPE_DC: + printf ("Node %d has node type DC\n", node_id); + break; + case ROM1394_NODE_TYPE_AVC: + printf ("Node %d has node type AVC\n", node_id); + print_avc_unit_info (handle, node_id); + + if (avc1394_check_subunit_type (handle, node_id, + AVC1394_SUBUNIT_TYPE_AUDIO)) + { + /* That's an interesting one... */ + plug_discovery (handle, node_id); + } + break; + case ROM1394_NODE_TYPE_SBP2: + printf ("Node %d has node type SBP2\n", node_id); + break; + case ROM1394_NODE_TYPE_CPU: + printf ("Node %d has node type CPU\n", node_id); + break; + default: + printf("No matching node type found for node %d\n", node_id); + } + } + + raw1394_destroy_handle (handle); + + return 0; +} + +/* + * Local variables: + * compile-command: "gcc -Wall -g -std=c99 -o detect_avc_unit detect_avc_unit.c -I/usr/local/include -L/usr/local/lib -lavc1394 -lrom1394 -lraw1394" + * End: + */ Index: /branches/libfreebob-1.4/freebob/tests/test-freebob-synctransfer.c =================================================================== --- /branches/libfreebob-1.4/freebob/tests/test-freebob-synctransfer.c (revision 96) +++ /branches/libfreebob-1.4/freebob/tests/test-freebob-synctransfer.c (revision 96) @@ -0,0 +1,745 @@ +/* + * FreeBob Test Program + * Copyright (C) 2005 Pieter Palmers + * + * Timing code shamelessly copied from Mixxx source code + * (C) 2002 by Tue and Ken Haste Andersen + */ + +/* Based upon code from: + * libiec61883 - Linux IEEE 1394 streaming media library. + * Copyright (C) 2004 Kristian Hogsberg and Dan Dennedy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * ./test-freebob-synctransfer + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + + #define QUATAFIRE_DEFAULT_SAMPLE_RATE 48000 + #define QUATAFIRE_OUT_DIMENSION 11 + #define QUATAFIRE_IN_DIMENSION 7 + #define QUATAFIRE_INPUT_TARGET_CHANNEL 1 + #define QUATAFIRE_MIDI_OUT_STREAM_POSITION 10 + +//enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_DEFAULT; +enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_BUFFERFILL; +//enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_PACKET_PER_BUFFER; +//#define BUFFER 1000 +//#define IRQ 20 +//#define PACKET_MAX 8192 + +#if __BYTE_ORDER == __BIG_ENDIAN + +struct iso_packet_header { + unsigned int data_length : 16; + unsigned int tag : 2; + unsigned int channel : 6; + unsigned int tcode : 4; + unsigned int sy : 4; +}; + +struct iec61883_packet { + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + unsigned char data[0]; +}; + +typedef struct packet_info packet_info_t; +struct packet_info { + /* The first part of this structure is a copy of the CIP header + * This can be memcpy'd from the packet itself. + */ + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + /* the second part is some extra info */ + unsigned int nevents; + unsigned int length; +}; + +#elif __BYTE_ORDER == __LITTLE_ENDIAN + +struct iso_packet_header { + unsigned int data_length : 16; + unsigned int channel : 6; + unsigned int tag : 2; + unsigned int sy : 4; + unsigned int tcode : 4; +}; + +struct iec61883_packet { + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + unsigned char data[0]; +}; + +typedef struct packet_info packet_info_t; +struct packet_info { + /* The first part of this structure is a copy of the CIP header + * This can be memcpy'd from the packet itself. + */ + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + /* the second part is some extra info */ + unsigned int nevents; + unsigned int length; +}; + + +#else + +#error Unknown bitfield type + +#endif + +typedef struct connection_info connection_info_t; +struct connection_info { + int packets; + int events; + int total_packets; + int total_events; + + int dropped; + + unsigned long handler_time; + + int packet_info_table_size; + packet_info_t *packet_info_table; + + connection_info_t *master; + + jack_ringbuffer_t *buffer; + +}; + +inline unsigned long getCurrentUTime() { + struct timeval now; + gettimeofday(&now, NULL); + return now.tv_sec*1000000+now.tv_usec; +} + +static int g_done = 0; + +static void sighandler (int sig) +{ + g_done = 1; +} + +static enum raw1394_iso_disposition +iso_master_receive_handler(raw1394handle_t handle, unsigned char *data, + unsigned int length, unsigned char channel, + unsigned char tag, unsigned char sy, unsigned int cycle, + unsigned int dropped) +{ + enum raw1394_iso_disposition retval; + + static unsigned int counter = 0; + int writelen; + unsigned long timestamp_enter=getCurrentUTime(); + + + connection_info_t *info = (connection_info_t *)raw1394_get_userdata(handle); + + struct iec61883_packet *packet = (struct iec61883_packet *) data; + + if(!info) { + fprintf(stderr,"invalid connection info handle"); + return RAW1394_ISO_ERROR; + } + + info->dropped+=dropped; + + if(info->packets< (info->packet_info_table_size)) { + // copy the packet_info from the packet to the packet_info_table + memcpy((void *)(&info->packet_info_table[info->packets]),packet,8); // the CIP header is 8 bytes long + + info->packet_info_table[info->packets].nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs; + info->packet_info_table[info->packets].length=length; + + // add the data payload to the ringbuffer + // rb_add(packet->data); + writelen= jack_ringbuffer_write(info->buffer, (const char *)(data+8), length - 8 ); + if(writelen < length-8) { + fprintf(stderr,"ringbuffer overrun\n"); + } + + // keep track of the total amount of events received + info->events+=info->packet_info_table[info->packets].nevents; + + // one packet received + info->packets++; + + //printf("MASTER RCV: FDF code = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n", packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, length,((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped); + retval=RAW1394_ISO_OK; + + } else { + // this shouldn't occur, because exiting raw_loop_iterate() should have freed up some space. + printf("MASTER RCV: Buffer overrun!\n"); + retval=RAW1394_ISO_ERROR; + } + + /* Check if the packet table is full. if so instruct libraw to leave raw1394_loop_iterate() + */ + if(info->packets==info->packet_info_table_size) { + // we processed this packet, but it is the last one we can queue in the packet_info_table. + // make sure we leave raw1394_loop_iterate() + retval=RAW1394_ISO_DEFER; + } + + info->handler_time+=(getCurrentUTime()-timestamp_enter); + + return retval; +} + +static enum raw1394_iso_disposition +iso_master_transmit_handler(raw1394handle_t handle, + unsigned char *data, unsigned int *len, + unsigned char *tag, unsigned char *sy, + int cycle, unsigned int dropped) +{ + int ret; + static unsigned int counter = 0; + + struct iec61883_packet *packet = (struct iec61883_packet *) data; + + if (counter++>16) { + printf("MASTER XMT: FDF code = %X. SYT = %10d, DBS = %10d, DBC = %10d\n", packet->fdf,packet->syt,packet->dbs,packet->dbc); + counter=0; + } + + return RAW1394_ISO_OK; +} + +static enum raw1394_iso_disposition +iso_slave_receive_handler(raw1394handle_t handle, unsigned char *data, + unsigned int length, unsigned char channel, + unsigned char tag, unsigned char sy, unsigned int cycle, + unsigned int dropped) +{ + + enum raw1394_iso_disposition retval; + + static unsigned int counter = 0; + + int readlen; + unsigned long timestamp_enter=getCurrentUTime(); + + connection_info_t *info = (connection_info_t *)raw1394_get_userdata(handle); + connection_info_t *master_info; + packet_info_t *master_packet_info; + + struct iec61883_packet *packet = (struct iec61883_packet *) data; + + if(!info) { + fprintf(stderr,"invalid connection info handle"); + return RAW1394_ISO_ERROR; + } + + master_info=info->master; + if(!master_info) { + fprintf(stderr,"invalid master connection info handle"); + return RAW1394_ISO_ERROR; + } + + info->dropped+=dropped; + + if(info->packets< (master_info->packet_info_table_size)) { + master_packet_info=&master_info->packet_info_table[info->packets]; + + // we process this packet, but it is the last one we can queue in the packet_info_table. + // make sure we leave raw1394_loop_iterate() + // copy the packet_info from the packet to the packet_info_table + memcpy((void *)(&info->packet_info_table[info->packets]),packet,8); // the CIP header is 8 bytes long + + //info->packet_info_table[info->packets].nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs; + info->packet_info_table[info->packets].length=length; + + // add the data payload to the ringbuffer + // rb_add(packet->data); + + // keep track of the total amount of events received + info->events+=info->packet_info_table[info->packets].nevents; + + // one packet received + info->packets++; + + // keep track of the total amount of events received + info->events+=master_packet_info->nevents; + //printf("SLAVE RCV: FDF code = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d, DROPPED = %6d\n", packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, length, dropped); + + retval=RAW1394_ISO_OK; + + } else { + // this shouldn't occur, because exiting raw_loop_iterate() should have freed up some space. + printf("SLAVE XMT: Buffer overrun!\n"); + retval=RAW1394_ISO_ERROR; + } + + /* Check if the packet table is full. if so instruct libraw to leave raw1394_loop_iterate() + */ + if(info->packets==(master_info->packet_info_table_size)) { + retval=RAW1394_ISO_DEFER; + } + + info->handler_time+=(getCurrentUTime()-timestamp_enter); + + return retval; +} + +static enum raw1394_iso_disposition +iso_slave_transmit_handler(raw1394handle_t handle, + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + int cycle, unsigned int dropped) +{ + enum raw1394_iso_disposition retval; + + static unsigned int counter = 0; + + int readlen; + unsigned long timestamp_enter=getCurrentUTime(); + + connection_info_t *info = (connection_info_t *)raw1394_get_userdata(handle); + connection_info_t *master_info; + packet_info_t *master_packet_info; + + struct iec61883_packet *packet = (struct iec61883_packet *) data; + + if(!info) { + fprintf(stderr,"invalid connection info handle"); + return RAW1394_ISO_ERROR; + } + + master_info=info->master; + if(!master_info) { + fprintf(stderr,"invalid master connection info handle"); + return RAW1394_ISO_ERROR; + } + + info->dropped+=dropped; + + if(info->packets< (master_info->packet_info_table_size)) { + master_packet_info=&master_info->packet_info_table[info->packets]; + + // copy the packet_info from the packet_info_table to the packet + memcpy(packet,(void *)(master_packet_info),8); // the CIP header is 8 bytes long + + *tag = 1; + *sy = 0; + *length=master_packet_info->length; + + // read the data payload from the ringbuffer + readlen=jack_ringbuffer_read(info->buffer, (const char *)(data+8), master_packet_info->length - 8 ); + if(readlen < master_packet_info->length - 8) { + fprintf(stderr,"ringbuffer underrun\n"); + } + + // one packet received + info->packets++; + + // keep track of the total amount of events received + info->events+=master_packet_info->nevents; + //printf("SLAVE XMT: FDF code = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n", packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,master_packet_info->nevents, dropped); + retval=RAW1394_ISO_OK; + + } else { + // this shouldn't occur, because exiting raw_loop_iterate() should have freed up some space. + printf("SLAVE XMT: Buffer overrun!\n"); + retval=RAW1394_ISO_ERROR; + } + + if(info->packets==(master_info->packet_info_table_size)) { + retval=RAW1394_ISO_DEFER; + } + + info->handler_time+=(getCurrentUTime()-timestamp_enter); + + return retval; +} + +int main (int argc, char *argv[]) +{ + raw1394handle_t master_receive_handle = raw1394_new_handle_on_port (0); + raw1394handle_t slave_transmit_handle = raw1394_new_handle_on_port (0); + raw1394handle_t slave_receive_handle = raw1394_new_handle_on_port (0); + + unsigned long timestamp_start; + unsigned long timestamp_wait_receive; + unsigned long timestamp_end_transmit; + + int irq=100; + int BUFFER=1000; + int PACKET_MAX=1024; + int TABLE_SIZE=8; + int PREBUFFER=0; + + int i; + + int master_receive_iso_channel; + int master_receive_bandwidth = -1; + int master_receive_iplug=-1; + int master_receive_oplug=0; + nodeid_t master_receive_node = 0xffc0; + + int slave_transmit_iso_channel; + int slave_transmit_bandwidth = -1; + int slave_transmit_iplug=0; + int slave_transmit_oplug=-1; + nodeid_t slave_transmit_node = 0xffc0; + + int slave_receive_iso_channel; + int slave_receive_bandwidth = -1; + int slave_receive_iplug=1; + int slave_receive_oplug=-1; + nodeid_t slave_receive_node = 0xffc0; + + jack_ringbuffer_t *ringbuffer; + + signal (SIGINT, sighandler); + signal (SIGPIPE, sighandler); + + for (i = 1; i < argc; i++) { + + if (strncmp (argv[i], "-h", 2) == 0 || + strncmp (argv[i], "--h", 3) == 0) + { + fprintf (stderr, + "usage: %s", argv[0]); + raw1394_destroy_handle (master_receive_handle); + raw1394_destroy_handle (slave_transmit_handle); + return 1; + } else if (strncmp (argv[i], "-b", 2) == 0) { + BUFFER = atoi (argv[++i]); + } else if (strncmp (argv[i], "-l", 2) == 0) { + PREBUFFER = atoi (argv[++i]); + } else if (strncmp (argv[i], "-p", 2) == 0) { + PACKET_MAX = atoi (argv[++i]); + } else if (strncmp (argv[i], "-t", 2) == 0) { + TABLE_SIZE = atoi (argv[++i]); + } else if (strncmp (argv[i], "-i", 2) == 0) { + irq = atoi (argv[++i]); + } + } + + + +//#define TABLE_SIZE 4 +//#define PREBUFFER 0 +#define RINGBUFFER_SIZE_EVENTS TABLE_SIZE * 11 * 8 // nb packets * frames/event * events/packet + + connection_info_t master_receive_connection_info; + memset(&master_receive_connection_info,'\0',sizeof(connection_info_t)); + master_receive_connection_info.packet_info_table_size=TABLE_SIZE; + + master_receive_connection_info.packet_info_table=calloc(master_receive_connection_info.packet_info_table_size,sizeof(packet_info_t)); + + if (!master_receive_connection_info.packet_info_table) { + fprintf (stderr, "Could not allocate memory for master packet info table\n"); + return -ENOMEM; + } + + connection_info_t slave_transmit_connection_info; + memset(&slave_transmit_connection_info,'\0',sizeof(connection_info_t)); + slave_transmit_connection_info.master=&master_receive_connection_info; + + connection_info_t slave_receive_connection_info; + memset(&slave_receive_connection_info,'\0',sizeof(connection_info_t)); + slave_receive_connection_info.master=&master_receive_connection_info; + slave_receive_connection_info.packet_info_table_size=TABLE_SIZE; + slave_receive_connection_info.packet_info_table=calloc(slave_receive_connection_info.packet_info_table_size,sizeof(packet_info_t)); + + if (!slave_receive_connection_info.packet_info_table) { + fprintf (stderr, "Could not allocate memory for slave receive packet info table\n"); + return -ENOMEM; + } + + if (master_receive_handle) { + + ringbuffer = jack_ringbuffer_create (RINGBUFFER_SIZE_EVENTS * sizeof (quadlet_t)); + master_receive_connection_info.buffer=ringbuffer; + slave_transmit_connection_info.buffer=ringbuffer; + + raw1394_set_userdata(master_receive_handle,&master_receive_connection_info); + + fprintf (stderr, "** Master receive...\n"); + fprintf (stderr, "Create CMP connection...\n"); + //channel = iec61883_cmp_connect (handle, raw1394_get_local_id (handle), &oplug, node, &iplug, &bandwidth); + master_receive_iso_channel = iec61883_cmp_connect (master_receive_handle, master_receive_node , &master_receive_oplug, raw1394_get_local_id (master_receive_handle), &master_receive_iplug, &master_receive_bandwidth); + + if (master_receive_iso_channel > -1) { + fprintf (stderr, "Init ISO master receive handler on channel %d...\n",master_receive_iso_channel); + fprintf (stderr, " other mode (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",BUFFER,PACKET_MAX, irq); + raw1394_iso_recv_init(master_receive_handle, iso_master_receive_handler, BUFFER, PACKET_MAX, master_receive_iso_channel, mode, irq); + + fprintf (stderr, "Start ISO master receive...\n"); + raw1394_iso_recv_start(master_receive_handle, -1, -1, 0); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + } + + if (slave_transmit_handle) { + fprintf (stderr, "** Slave transmit...\n"); + raw1394_set_userdata(slave_transmit_handle,&slave_transmit_connection_info); + fprintf (stderr, "Create CMP connection...\n"); + + slave_transmit_iso_channel = iec61883_cmp_connect (slave_transmit_handle, raw1394_get_local_id (slave_transmit_handle), &slave_transmit_oplug, slave_transmit_node, &slave_transmit_iplug, &slave_transmit_bandwidth); + + if (slave_transmit_iso_channel > -1) { + fprintf (stderr, "Init ISO slave transmit handler on channel %d...\n",slave_transmit_iso_channel); + fprintf (stderr, " other mode (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",BUFFER,PACKET_MAX, irq); + raw1394_iso_xmit_init(slave_transmit_handle, iso_slave_transmit_handler, BUFFER, PACKET_MAX, slave_transmit_iso_channel, RAW1394_ISO_SPEED_400, irq); + + fprintf (stderr, "Start ISO slave transmit... PREBUFFER=%d\n",PREBUFFER); + raw1394_iso_xmit_start(slave_transmit_handle, -1, PREBUFFER); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + } + } else { + fprintf (stderr, "Failed to get transmit libraw1394 handle\n %d: %s\nContinuing without transmitting\n",errno,strerror(errno)); + } + + if (slave_receive_handle) { + fprintf (stderr, "** Slave receive...\n"); + + raw1394_set_userdata(slave_receive_handle,&slave_receive_connection_info); + + fprintf (stderr, "Create CMP connection...\n"); + + slave_receive_iso_channel = iec61883_cmp_connect (slave_receive_handle, slave_receive_node , &slave_receive_oplug, raw1394_get_local_id (slave_receive_handle), &slave_receive_iplug, &slave_receive_bandwidth); + + if (slave_receive_iso_channel > -1) { + fprintf (stderr, "Init ISO slave receive handler on channel %d...\n",slave_receive_iso_channel); + fprintf (stderr, " other mode (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",BUFFER,PACKET_MAX, irq); + raw1394_iso_xmit_init(slave_receive_handle, iso_slave_receive_handler, BUFFER, PACKET_MAX, slave_receive_iso_channel, RAW1394_ISO_SPEED_400, irq); + + fprintf (stderr, "Start ISO slave receive... PREBUFFER=%d\n",PREBUFFER); + raw1394_iso_xmit_start(slave_receive_handle, -1, PREBUFFER); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + } + } else { + fprintf (stderr, "Failed to get slave receive libraw1394 handle\n %d: %s\nContinuing without receiving slave stream\n",errno,strerror(errno)); + } + + fprintf (stderr, "Running raw1394_loop_iterate()...\n"); + + int packetcount=0; + +// polled receive loop + while (!g_done) { + int i=0,j=0; + // wait for enough packets + timestamp_start=getCurrentUTime(); + while ((raw1394_loop_iterate(master_receive_handle) == 0) && (master_receive_connection_info.packets < TABLE_SIZE)) { + + i++; + } + timestamp_wait_receive=getCurrentUTime(); + + /*printf("LOOP: i = %4d. packets = %4d, events = %4d, total_packets = %6d, total_events = %6d, dropped = %6d\n", + i, + master_receive_connection_info.packets, + master_receive_connection_info.events, + master_receive_connection_info.total_packets, + master_receive_connection_info.total_events, + master_receive_connection_info.dropped); + */ + //printf(" rb_readspace = %6d, rb_writespace = %6d\n",jack_ringbuffer_read_space(ringbuffer),jack_ringbuffer_write_space(ringbuffer)); + + if(slave_transmit_handle) { + j=0; + while ((raw1394_loop_iterate(slave_transmit_handle) == 0) && (slave_transmit_connection_info.packets < master_receive_connection_info.packets )) { + + j++; + } + + /*printf(" j = %4d. packets = %4d, events = %4d, total_packets = %6d, total_events = %6d, dropped = %6d\n", + j, + slave_transmit_connection_info.packets, + slave_transmit_connection_info.events, + slave_transmit_connection_info.total_packets, + slave_transmit_connection_info.total_events, + slave_transmit_connection_info.dropped); + */ + // consume + slave_transmit_connection_info.total_packets+=slave_transmit_connection_info.packets; + slave_transmit_connection_info.total_events+=slave_transmit_connection_info.events; + slave_transmit_connection_info.packets=0; + slave_transmit_connection_info.events=0; + + } + timestamp_end_transmit=getCurrentUTime(); + + if(0 && slave_receive_handle) { + j=0; + while ((raw1394_loop_iterate(slave_receive_handle) == 0) && (slave_receive_connection_info.packets < master_receive_connection_info.packets )) { + + j++; + } + + /*printf(" j = %4d. packets = %4d, events = %4d, total_packets = %6d, total_events = %6d, dropped = %6d\n", + j, + slave_receive_connection_info.packets, + slave_receive_connection_info.events, + slave_receive_connection_info.total_packets, + slave_receive_connection_info.total_events, + slave_receive_connection_info.dropped); + */ + // consume + slave_receive_connection_info.total_packets+=slave_receive_connection_info.packets; + slave_receive_connection_info.total_events+=slave_receive_connection_info.events; + slave_receive_connection_info.packets=0; + slave_receive_connection_info.events=0; + + } + + // consume + master_receive_connection_info.total_packets+=master_receive_connection_info.packets; + master_receive_connection_info.total_events+=master_receive_connection_info.events; + master_receive_connection_info.packets=0; + master_receive_connection_info.events=0; + + fprintf(stderr,"%06.03f %06.03f %06.03f %06.03f\r", + (float)(master_receive_connection_info.handler_time/master_receive_connection_info.total_packets/1000.0), + (float)(slave_transmit_connection_info.handler_time/slave_transmit_connection_info.total_packets/1000.0), + (float)(timestamp_wait_receive/1000.0-timestamp_start/1000.0), + (float)(timestamp_end_transmit/1000.0-timestamp_wait_receive/1000.0) + ); + //printf(" rb_readspace = %6d, rb_writespace = %6d\n",jack_ringbuffer_read_space(ringbuffer),jack_ringbuffer_write_space(ringbuffer)); + } + + + fprintf (stderr, "Shutdown...\n"); + raw1394_iso_stop(master_receive_handle); + raw1394_iso_shutdown(master_receive_handle); + + if (slave_transmit_handle) { + raw1394_iso_stop(slave_transmit_handle); + raw1394_iso_shutdown(slave_transmit_handle); + } + + if (slave_receive_handle) { + raw1394_iso_stop(slave_receive_handle); + raw1394_iso_shutdown(slave_receive_handle); + } + + fprintf (stderr, "Closing CMP connection...\n"); + if (slave_transmit_handle) { + iec61883_cmp_disconnect (slave_transmit_handle, raw1394_get_local_id (slave_transmit_handle), slave_transmit_oplug, slave_transmit_node, slave_transmit_iplug, slave_transmit_iso_channel, slave_transmit_bandwidth); + } + + if (slave_receive_handle) { + iec61883_cmp_disconnect (slave_receive_handle, slave_receive_node, slave_receive_oplug, raw1394_get_local_id (slave_receive_handle), slave_receive_iplug, slave_receive_iso_channel, slave_receive_bandwidth); + } + + iec61883_cmp_disconnect (master_receive_handle, master_receive_node, master_receive_oplug, raw1394_get_local_id (master_receive_handle), master_receive_iplug, master_receive_iso_channel, master_receive_bandwidth); + raw1394_destroy_handle(master_receive_handle); + + if (slave_transmit_handle) { + raw1394_destroy_handle(slave_transmit_handle); + } + if (slave_receive_handle) { + raw1394_destroy_handle(slave_receive_handle); + } + + jack_ringbuffer_free(ringbuffer); + + } else { + fprintf (stderr, "Failed to get libraw1394 handle\n %d: %s\n",errno,strerror(errno)); + return -1; + } + + return 0; +} Index: /branches/libfreebob-1.4/freebob/tests/test-freebob-midi.c =================================================================== --- /branches/libfreebob-1.4/freebob/tests/test-freebob-midi.c (revision 81) +++ /branches/libfreebob-1.4/freebob/tests/test-freebob-midi.c (revision 81) @@ -0,0 +1,522 @@ +/* + * FreeBob Test Program + * Copyright (C) 2005 Pieter Palmers + * Parts of this code (C) M. Nagorni + */ + +/* Based upon code from: + * libiec61883 - Linux IEEE 1394 streaming media library. + * Copyright (C) 2004 Kristian Hogsberg and Dan Dennedy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +static int g_done = 0; + + // QUATAFIRE specific: + #define QUATAFIRE_MIDI_IN_STREAM_POSITION 6 + #define QUATAFIRE_MIDI_OUT_STREAM_POSITION 10 + #define QUATAFIRE_DEFAULT_SAMPLE_RATE 48000 + #define QUATAFIRE_OUT_DIMENSION 11 + + #define IEC61883_AM824_LABEL_MIDI_NO_DATA 0x80 + #define IEC61883_AM824_LABEL_MIDI_1X 0x81 + #define IEC61883_AM824_LABEL_MIDI_2X 0x82 + #define IEC61883_AM824_LABEL_MIDI_3X 0x83 + + #define ALSA_SEQ_BUFF_SIZE 1024 + #define MAX_MIDI_PORTS 2 + #define MIDI_TRANSMIT_BUFFER_SIZE 1024 + +typedef struct { + int seq_port_nr; + snd_midi_event_t *parser; +} freebob_midi_port_t; + +typedef struct { + snd_seq_t *seq_handle; + int nb_seq_ports; + freebob_midi_port_t *ports[MAX_MIDI_PORTS]; +} freebob_midi_ports_t; + +int open_seq(snd_seq_t **seq_handle, int in_ports[], int out_ports[], int num_in, int num_out); + +/* Open ALSA sequencer with num_in writeable ports and num_out readable ports. */ +/* The sequencer handle and the port IDs are returned. */ +int open_seq(snd_seq_t **seq_handle, int in_ports[], int out_ports[], int num_in, int num_out) { + + int l1; + char portname[64]; + + if (snd_seq_open(seq_handle, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) { + fprintf(stderr, "Error opening ALSA sequencer.\n"); + return(-1); + } + snd_seq_set_client_name(*seq_handle, "FreeBob MIDI I/O test"); + for (l1 = 0; l1 < num_in; l1++) { + sprintf(portname, "MIDI OUT %d", l1); + if ((in_ports[l1] = snd_seq_create_simple_port(*seq_handle, portname, + SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, + SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) { + fprintf(stderr, "Error creating sequencer port.\n"); + return(-1); + } + } + for (l1 = 0; l1 < num_out; l1++) { + sprintf(portname, "MIDI IN %d", l1); + if ((out_ports[l1] = snd_seq_create_simple_port(*seq_handle, portname, + SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, + SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) { + fprintf(stderr, "Error creating sequencer port.\n"); + return(-1); + } + } + return(0); +} + +static void sighandler (int sig) +{ + g_done = 1; +} + +int fill_packet(iec61883_amdtp_t amdtp, + char *data, + int nevents, + unsigned int dbc, + unsigned int dropped, + void *callback_data) +{ + + snd_seq_event_t *ev; + + freebob_midi_ports_t *f = (freebob_midi_ports_t*) callback_data; + + static int total_packets = 0; + int i; + int j; + char *current_pos_in_buffer=data; + quadlet_t test=0; + + static int bytes_to_send=0; + static int next_byte_to_send; + static unsigned char work_buffer[MIDI_TRANSMIT_BUFFER_SIZE]; + + int current_midi_port; + + for (i=0; i < nevents; ++i) { // cycle through all events requested + + current_midi_port=(dbc+i)%8; // calculate the current MIDI port + + current_pos_in_buffer=data+i*QUATAFIRE_OUT_DIMENSION*sizeof(quadlet_t); + + test = 0x40 << 24; // empty MBLA value + + // fill up all streams with the empty value + for (j=0; jports[current_midi_port] + && f->ports[current_midi_port]->parser) { + + // are we still sending a previously decoded event? + if (bytes_to_send==0) { // get the next event, if present + + // get next event, if one is present + if ((snd_seq_event_input(f->seq_handle, &ev) > 0)) { + // decode it to the work buffer + if((bytes_to_send = snd_midi_event_decode ( f->ports[current_midi_port]->parser, + work_buffer, + MIDI_TRANSMIT_BUFFER_SIZE, + ev))<0) + { // failed + fprintf (stderr, "Error decoding event for port %d (errcode=%d)\n", current_midi_port,bytes_to_send); + bytes_to_send=0; + //return -1; + } + // decoding succeeded + next_byte_to_send=0; + } else { + // do nothing + } + } + // check if we need to send a byte + if (bytes_to_send>0) { + test = 0x81 << 24 | (work_buffer[next_byte_to_send] << 16); + //fprintf (stderr, "sending 0x%08X\n", test); + + bytes_to_send--; + next_byte_to_send++; + + } else { + // send empty data + test = 0x80 << 24; + } + + + } else if (current_midi_port==1) { + //test= 0x81 << 24 | 0xFE0000; // send out a 0xFE message + test = 0x80 << 24; + } else { + test = 0x80 << 24; + } + + /* + but for now this will have to do: + */ + /*if (current_midi_port == 1) { + test= 0x81 << 24 | 0xFE0000; // compose the event + } else { + test= 0x80 << 24; // compose the event + }*/ + + memcpy(current_pos_in_buffer,&test,sizeof(quadlet_t)); + + } + + total_packets++; + + if ((total_packets & 0xfff) == 0) { + fprintf (stderr, "\r%10d packets", total_packets); + fflush (stderr); + } + + return 0; +} + +static int read_packet(iec61883_amdtp_t amdtp, + char *data, + int nsamples, + unsigned int dbc, + unsigned int dropped, + void *callback_data) +{ + freebob_midi_ports_t *f = (freebob_midi_ports_t*) callback_data; + snd_seq_event_t ev; + + quadlet_t *events=(quadlet_t*) data; + quadlet_t this_event; + + static int total_packets = 0; + + int i, dimension; + + dimension = iec61883_amdtp_get_dimension(amdtp); + + // as long as the device sends clusters of 8 events, the dbc=0 is ok + // DBC should be available though + + if (total_packets == 0) + fprintf (stderr, "channels=%d", + dimension); + + if (f) { // if the callback data pointer is valid + for (i=0; i>24; + + if (nbbytes && midi_port < MAX_MIDI_PORTS && f->ports[midi_port]) { + // read the bytes + while(nbbytes--) { + /* the next line replaces: + int byte1=(this_event & 0x00FF0000) >>16; + int byte2=(this_event & 0x0000FF00) >>8; + int byte3=(this_event & 0x000000FF); + + remark: it isn't possible to have e.g. byte2 valid without byte1 valid + */ + int byte=(this_event >> (8 * (2-nbbytes))) & 0xFF; + if ((snd_midi_event_encode_byte(f->ports[midi_port]->parser,byte, &ev)) > 0) { + // a midi message is complete, send it out to ALSA + snd_seq_ev_set_subs(&ev); + snd_seq_ev_set_direct(&ev); + snd_seq_ev_set_source(&ev, f->ports[midi_port]->seq_port_nr); + snd_seq_event_output_direct(f->seq_handle, &ev); + } + } + } + } else { + fprintf (stderr, "Receive error: not a MIDI event 0x%08X\n", this_event); + } + } + } + + total_packets++; + + if ((total_packets & 0xfff) == 0) { + fprintf (stderr, "\r%10d packets, %d samples/packet (last packet)", total_packets,nsamples); + fflush (stderr); + } + return 0; +} + +static void amdtp_receive( raw1394handle_t handle, freebob_midi_ports_t *f, int channel) +{ + iec61883_amdtp_t amdtp = iec61883_amdtp_recv_init (handle, read_packet, (void *)f ); + + // lowering the buffers is nescessary in order to get rid of the lag. + // should be as low as possible i guess, but i can't get much lower than 300 + // maybe RT priority will help at some point? + iec61883_amdtp_set_buffers(amdtp,300); + + if ( amdtp && iec61883_amdtp_recv_start (amdtp, channel) == 0) + { + int fd = raw1394_get_fd (handle); + struct timeval tv; + fd_set rfds; + int result = 0; + + signal (SIGINT, sighandler); + signal (SIGPIPE, sighandler); + + fprintf (stderr, "Starting to receive\n"); + + do { + FD_ZERO (&rfds); + FD_SET (fd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 20000; + + if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0) + result = raw1394_loop_iterate (handle); + + } while (g_done == 0 && result == 0); + + fprintf (stderr, "\ndone.\n"); + } + iec61883_amdtp_close (amdtp); +} + +static void amdtp_transmit( raw1394handle_t handle, freebob_midi_ports_t *f, int channel) +{ + iec61883_amdtp_t amdtp; + + amdtp = iec61883_amdtp_xmit_init (handle, QUATAFIRE_DEFAULT_SAMPLE_RATE, + IEC61883_AMDTP_FORMAT_RAW, + IEC61883_AMDTP_INPUT_LE24, + IEC61883_MODE_BLOCKING_EMPTY, + QUATAFIRE_OUT_DIMENSION, + fill_packet, (void *)f ); + + if (amdtp && iec61883_amdtp_xmit_start (amdtp, channel) == 0) + { + int fd = raw1394_get_fd (handle); + struct timeval tv; + fd_set rfds; + int result = 0; + + signal (SIGINT, sighandler); + signal (SIGPIPE, sighandler); + fprintf (stderr, "Starting to transmit\n"); + + do { + FD_ZERO (&rfds); + FD_SET (fd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 20000; + + if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0) + result = raw1394_loop_iterate (handle); + + } while (g_done == 0 && result == 0); + + fprintf (stderr, "\ndone.\n"); + } + iec61883_amdtp_close (amdtp); +} + +int main (int argc, char *argv[]) +{ + raw1394handle_t handle = raw1394_new_handle_on_port (0); + nodeid_t node = 0xffc0; + + int iplug=-1; + int oplug=-1; + + int is_transmit = 0; + int node_specified = 0; + int i; + int channel; + int bandwidth = -1; + + // setup the ALSA midi seq clients + snd_seq_t *seq_handle; + int in_ports[MAX_MIDI_PORTS], out_ports[MAX_MIDI_PORTS]; + + freebob_midi_ports_t midi_in_ports; + freebob_midi_ports_t midi_out_ports; + + for (i = 1; i < argc; i++) { + + if (strncmp (argv[i], "-h", 2) == 0 || + strncmp (argv[i], "--h", 3) == 0) + { + fprintf (stderr, + "usage: %s [[-r | -t] node-id]\n", argv[0]); + raw1394_destroy_handle (handle); + return 1; + } else if (strncmp (argv[i], "-t", 2) == 0) { + node |= atoi (argv[++i]); + is_transmit = 1; + node_specified = 1; + } else if (strncmp (argv[i], "-r", 2) == 0) { + node |= atoi (argv[++i]); + is_transmit = 0; + node_specified = 1; + } else if (!node_specified) { + is_transmit = 1; + } + } + + // open sequencer + // the number of midi ports is statically set to 2 + if (open_seq(&seq_handle, in_ports, out_ports, 2, 2) < 0) { + fprintf(stderr, "ALSA Error.\n"); + raw1394_destroy_handle (handle); + exit(1); + } + + for(i=0;iseq_port_nr=out_ports[i]; + midi_in_ports.ports[i]=midi_in_port; + if (snd_midi_event_new ( ALSA_SEQ_BUFF_SIZE, &(midi_in_port->parser)) < 0) { + fprintf(stderr, "ALSA Error: could not init parser for MIDI IN port %d\n",i); + exit(1); // this too + } + } + + midi_out_port=malloc(sizeof(freebob_midi_port_t)); + if(!midi_out_port) { + fprintf(stderr, "Could not allocate memory for MIDI OUT port %d\n",i); + exit(1); // this could be/is a memory leak, I know... + } else { + midi_out_port->seq_port_nr=in_ports[i]; + midi_out_ports.ports[i]=midi_out_port; + if (snd_midi_event_new ( ALSA_SEQ_BUFF_SIZE, &(midi_out_port->parser)) < 0) { + fprintf(stderr, "ALSA Error: could not init parser for MIDI OUT port %d\n",i); + exit(1); // this too + } + } + } + + midi_in_ports.nb_seq_ports=MAX_MIDI_PORTS; + midi_in_ports.seq_handle=seq_handle; + + midi_out_ports.nb_seq_ports=MAX_MIDI_PORTS; + midi_out_ports.seq_handle=seq_handle; + + if (handle) { + if (is_transmit) { + if (node_specified) { + channel = iec61883_cmp_connect (handle, + raw1394_get_local_id (handle), &oplug, node, &iplug, &bandwidth); + if (channel > -1) { + amdtp_transmit (handle, &midi_out_ports, channel); + iec61883_cmp_disconnect (handle, + raw1394_get_local_id (handle), oplug, node, iplug, channel, bandwidth); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + amdtp_transmit (handle, &midi_out_ports, 63); + } + } else { + amdtp_transmit (handle, &midi_out_ports, 63); + } + } else { + if (node_specified) { + channel = iec61883_cmp_connect (handle, node, &oplug, + raw1394_get_local_id (handle), &iplug, &bandwidth); + if (channel > -1) { + amdtp_receive (handle, &midi_in_ports, channel); + iec61883_cmp_disconnect (handle, node, oplug, + raw1394_get_local_id (handle), iplug, channel, bandwidth); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + amdtp_receive (handle, &midi_in_ports, 63); + } + } else { + amdtp_receive (handle, &midi_in_ports, 63); + } + } + raw1394_destroy_handle (handle); + } else { + fprintf (stderr, "Failed to get libraw1394 handle\n"); + return -1; + } + + // free the MIDI to seq parsers and port structures + for(i=0;iparser ); + free(midi_in_port); + } + if(midi_out_port) { + snd_midi_event_free ( midi_out_port->parser ); + free(midi_out_port); + } + } + + return 0; +} Index: /branches/libfreebob-1.4/freebob/tests/stream_format.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/stream_format.cpp (revision 113) +++ /branches/libfreebob-1.4/freebob/tests/stream_format.cpp (revision 113) @@ -0,0 +1,448 @@ +/* stream_format.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "avc_extended_stream_format.h" +#include "serialize.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +//////////////////////////////////////////////// +// arg parsing +//////////////////////////////////////////////// +const char *argp_program_version = "stream_format 0.1"; +const char *argp_program_bug_address = ""; +static char doc[] = "stream_format -- get/set test program for FreeBob"; +static char args_doc[] = "NODE_ID PLUG_ID"; +static struct argp_option options[] = { + {"verbose", 'v', 0, 0, "Produce verbose output" }, + {"test", 't', 0, 0, "Do tests instead get/set action" }, + {"direction", 'd', "DIRECTION", 0, "Specify plug direction [0 = Input plug (playback), 1 = Output plug (capture)]" }, + {"frequency", 'f', "FREQUENCY", 0, "Set frequency" }, + {"port", 'p', "PORT", 0, "Set port" }, + { 0 } +}; + +struct arguments +{ + arguments() + : verbose( false ) + , test( false ) + , frequency( 0 ) + , direction ( 0 ) + , port( 0 ) + { + args[0] = 0; + args[1] = 0; + } + + char* args[2]; + bool verbose; + bool test; + int frequency; + int direction; + int port; +} arguments; + +// Parse a single option. +static error_t +parse_opt( int key, char* arg, struct argp_state* state ) +{ + // Get the input argument from `argp_parse', which we + // know is a pointer to our arguments structure. + struct arguments* arguments = ( struct arguments* ) state->input; + + char* tail; + switch (key) { + case 'v': + arguments->verbose = true; + break; + case 't': + arguments->test = true; + break; + case 'f': + errno = 0; + arguments->frequency = strtol(arg, &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return errno; + } + break; + case 'p': + errno = 0; + arguments->port = strtol(arg, &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return errno; + } + break; + case 'd': + errno = 0; + arguments->direction = strtol(arg, &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return errno; + } + break; + case ARGP_KEY_ARG: + if (state->arg_num >= 2) { + // Too many arguments. + argp_usage (state); + } + arguments->args[state->arg_num] = arg; + break; + case ARGP_KEY_END: + if (state->arg_num < 2) { + // Not enough arguments. + argp_usage (state); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { options, parse_opt, args_doc, doc }; + + +//////////////////////////////////////// +// Test application +//////////////////////////////////////// +void +doTest(raw1394handle_t handle, int node_id, int plug_id) +{ + + ExtendedStreamFormatCmd extendedStreamFormatCmd = ExtendedStreamFormatCmd( ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommandList ); + UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, plug_id ); + extendedStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input, + PlugAddress::ePAM_Unit, + unitPlugAddress ) ); + extendedStreamFormatCmd.setVerbose( arguments.verbose ); + extendedStreamFormatCmd.setCommandType( AVCCommand::eCT_Status ); + + extendedStreamFormatCmd.setIndexInStreamFormat( 0 ); + extendedStreamFormatCmd.fire( handle, node_id ); + extendedStreamFormatCmd.setIndexInStreamFormat( 1 ); + extendedStreamFormatCmd.fire( handle, node_id ); + extendedStreamFormatCmd.setIndexInStreamFormat( 2 ); + extendedStreamFormatCmd.fire( handle, node_id ); + extendedStreamFormatCmd.setIndexInStreamFormat( 3 ); + extendedStreamFormatCmd.fire( handle, node_id ); + extendedStreamFormatCmd.setIndexInStreamFormat( 4 ); + extendedStreamFormatCmd.fire( handle, node_id ); + + ExtendedStreamFormatCmd extendedStreamFormatCmdS = ExtendedStreamFormatCmd(); + extendedStreamFormatCmdS.setPlugAddress( PlugAddress( PlugAddress::ePD_Input, + PlugAddress::ePAM_Unit, + unitPlugAddress ) ); + extendedStreamFormatCmdS.setVerbose( arguments.verbose ); + extendedStreamFormatCmdS.setCommandType( AVCCommand::eCT_Status ); + + if ( extendedStreamFormatCmdS.fire( handle, node_id ) ) { + CoutSerializer se; + extendedStreamFormatCmdS.serialize( se ); + } + + return; +} + +//////////////////////////////////////// +// Main application +//////////////////////////////////////// +struct FormatInfo { + FormatInfo() + : m_freq( eSF_DontCare ) + , m_format( 0 ) + , m_audioChannels( 0 ) + , m_midiChannels( 0 ) + , m_index( 0 ) + {} + + ESamplingFrequency m_freq; + int m_format; // 0 = compound, 1 = sync + int m_audioChannels; + int m_midiChannels; + int m_index; +}; +typedef std::vector< struct FormatInfo > FormatInfoVector; + +std::ostream& operator<<( std::ostream& stream, FormatInfo info ) +{ + stream << info.m_freq << " Hz ("; + if ( info.m_format ) { + stream << "sync "; + } else { + stream << "compound "; + } + stream << "stream, "; + stream << "audio channels: " << info.m_audioChannels + << ", midi channels: " << info.m_midiChannels << ")"; + return stream; +} + +FormatInfo +createFormatInfo( ExtendedStreamFormatCmd& cmd ) +{ + FormatInfo fi; + + FormatInformationStreamsSync* syncStream + = dynamic_cast< FormatInformationStreamsSync* > ( cmd.getFormatInformation()->m_streams ); + if ( syncStream ) { + fi.m_freq = static_cast( syncStream->m_samplingFrequency ); + fi.m_format = 1; + } + + FormatInformationStreamsCompound* compoundStream + = dynamic_cast< FormatInformationStreamsCompound* > ( cmd.getFormatInformation()->m_streams ); + if ( compoundStream ) { + fi.m_freq = static_cast( compoundStream->m_samplingFrequency ); + fi.m_format = 0; + for ( int j = 0; j < compoundStream->m_numberOfStreamFormatInfos; ++j ) + { + switch ( compoundStream->m_streamFormatInfos[j]->m_streamFormat ) { + case AVC1394_STREAM_FORMAT_AM824_MULTI_BIT_LINEAR_AUDIO_RAW: + fi.m_audioChannels += compoundStream->m_streamFormatInfos[j]->m_numberOfChannels; + break; + case AVC1394_STREAM_FORMAT_AM824_MIDI_CONFORMANT: + fi.m_midiChannels += compoundStream->m_streamFormatInfos[j]->m_numberOfChannels; + break; + default: + std::cout << "addStreamFormat: unknown stream format for channel (" << j << ")" << std::endl; + } + } + } + fi.m_index = cmd.getIndex(); + return fi; +} + +bool +doApp(raw1394handle_t handle, int node_id, int plug_id, PlugAddress::EPlugDirection direction = PlugAddress::ePD_Input , ESamplingFrequency frequency = eSF_DontCare) +{ + ExtendedStreamFormatCmd extendedStreamFormatCmd = ExtendedStreamFormatCmd( ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommandList ); + UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, plug_id ); + + extendedStreamFormatCmd.setPlugAddress( PlugAddress( direction, + PlugAddress::ePAM_Unit, + unitPlugAddress ) ); + extendedStreamFormatCmd.setVerbose( arguments.verbose ); + + int i = 0; + FormatInfoVector supportedFormatInfos; + bool cmdSuccess = false; + + do { + extendedStreamFormatCmd.setIndexInStreamFormat( i ); + extendedStreamFormatCmd.setCommandType( AVCCommand::eCT_Status ); + cmdSuccess = extendedStreamFormatCmd.fire( handle, node_id ); + if ( cmdSuccess + && ( extendedStreamFormatCmd.getResponse() == AVCCommand::eR_Implemented ) ) + { + supportedFormatInfos.push_back( createFormatInfo( extendedStreamFormatCmd ) ); + } + ++i; + } while ( cmdSuccess && ( extendedStreamFormatCmd.getResponse() == ExtendedStreamFormatCmd::eR_Implemented ) ); + + if ( !cmdSuccess ) { + std::cerr << "Failed to retrieve format infos" << std::endl; + return false; + } + + std::cout << "Supported frequencies:" << std::endl; + for ( FormatInfoVector::iterator it = supportedFormatInfos.begin(); + it != supportedFormatInfos.end(); + ++it ) + { + std::cout << " " << *it << std::endl; + } + + if ( frequency != eSF_DontCare ) { + std::cout << "Trying to set frequency (" << frequency << "): " << std::endl; + + FormatInfoVector::iterator it; + for ( it = supportedFormatInfos.begin(); + it != supportedFormatInfos.end(); + ++it ) + { + if ( it->m_freq == frequency ) { + std::cout << " - frequency " << frequency << " is supported" << std::endl; + + ExtendedStreamFormatCmd setFormatCmd = ExtendedStreamFormatCmd( ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommandList ); + setFormatCmd.setVerbose( arguments.verbose ); + setFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input, + PlugAddress::ePAM_Unit, + unitPlugAddress ) ); + + setFormatCmd.setIndexInStreamFormat( it->m_index ); + setFormatCmd.setCommandType( AVCCommand::eCT_Status ); + if ( !setFormatCmd.fire( handle, node_id ) ) { + std::cout << " - failed to retrieve format for index " << it->m_index << std::endl; + return false; + } + + std::cout << " - " << createFormatInfo( setFormatCmd ) << std::endl; + + setFormatCmd.setSubFunction( ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommand ); + setFormatCmd.setCommandType( AVCCommand::eCT_Control ); + if ( !setFormatCmd.fire( handle, node_id ) ) { + std::cout << " - failed to set new format" << std::endl; + return false; + } + std::cout << " - configuration operation succedded" << std::endl; + break; + } + } + if ( it == supportedFormatInfos.end() ) { + std::cout << " - frequency not supported by device. Operation failed" << std::endl; + } + } + + ExtendedStreamFormatCmd currentFormat = ExtendedStreamFormatCmd(); + currentFormat.setPlugAddress( PlugAddress( PlugAddress::ePD_Input, + PlugAddress::ePAM_Unit, + unitPlugAddress ) ); + currentFormat.setVerbose( arguments.verbose ); + currentFormat.setCommandType( AVCCommand::eCT_Status ); + + if ( currentFormat.fire( handle, node_id ) ) { + std::cout << "Configured frequency: " << createFormatInfo( currentFormat ) << std::endl; + } + + return true; +} + +/////////////////////////////////////////////////////////////// +ESamplingFrequency +parseFrequencyString( int frequency ) +{ + ESamplingFrequency efreq; + switch ( frequency ) { + case 22050: + efreq = eSF_22050Hz; + break; + case 24000: + efreq = eSF_24000Hz; + break; + case 32000: + efreq = eSF_32000Hz; + break; + case 44100: + efreq = eSF_44100Hz; + break; + case 48000: + efreq = eSF_48000Hz; + break; + case 88200: + efreq = eSF_88200Hz; + break; + case 96000: + efreq = eSF_96000Hz; + break; + case 176400: + efreq = eSF_176400Hz; + break; + case 192000: + efreq = eSF_192000Hz; + break; + default: + efreq = eSF_DontCare; + } + + return efreq; +} + +PlugAddress::EPlugDirection +parseDirectionString( int frequency ) +{ + PlugAddress::EPlugDirection edir; + switch ( frequency ) { + case 0: + edir = PlugAddress::ePD_Input; + break; + case 1: + edir = PlugAddress::ePD_Output; + break; + default: + edir = PlugAddress::ePD_Input; + } + + return edir; +} + +int +main(int argc, char **argv) +{ + // arg parsing + argp_parse (&argp, argc, argv, 0, 0, &arguments); + + errno = 0; + char* tail; + int node_id = strtol(arguments.args[0], &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return -1; + } + int plug_id = strtol(arguments.args[1], &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return -1; + } + + // create raw1394handle + raw1394handle_t handle; + handle = raw1394_new_handle (); + if (!handle) { + if (!errno) { + perror("lib1394raw not compatable\n"); + } else { + fprintf(stderr, "Could not get 1394 handle"); + fprintf(stderr, "Is ieee1394, driver, and raw1394 loaded?\n"); + } + return -1; + } + + if (raw1394_set_port(handle, arguments.port) < 0) { + fprintf(stderr, "Could not set port"); + raw1394_destroy_handle (handle); + return -1; + } + + if ( arguments.test ) { + doTest( handle, node_id, plug_id ); + } else { + ESamplingFrequency efreq = parseFrequencyString( arguments.frequency ); + PlugAddress::EPlugDirection edir = parseDirectionString( arguments.direction ); + + doApp( handle, node_id, plug_id, edir, efreq ); + } + + raw1394_destroy_handle( handle ); + + return 0; +} Index: /branches/libfreebob-1.4/freebob/tests/avc_definitions.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_definitions.cpp (revision 107) +++ /branches/libfreebob-1.4/freebob/tests/avc_definitions.cpp (revision 107) @@ -0,0 +1,59 @@ +/* avc_defintions.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "avc_definitions.h" + +std::ostream& operator<<( std::ostream& stream, ESamplingFrequency freq ) +{ + char* str; + switch ( freq ) { + case eSF_22050Hz: + str = "22050"; + break; + case eSF_24000Hz: + str = "24000"; + break; + case eSF_32000Hz: + str = "32000"; + break; + case eSF_44100Hz: + str = "44100"; + break; + case eSF_48000Hz: + str = "48000"; + break; + case eSF_88200Hz: + str = "88200"; + break; + case eSF_96000Hz: + str = "96000"; + break; + case eSF_176400Hz: + str = "176400"; + break; + case eSF_192000Hz: + str = "192000"; + break; + case eSF_DontCare: + default: + str = "unknown"; + } + return stream << str; +}; Index: /branches/libfreebob-1.4/freebob/tests/avc_generic.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_generic.cpp (revision 119) +++ /branches/libfreebob-1.4/freebob/tests/avc_generic.cpp (revision 119) @@ -0,0 +1,117 @@ +/* avc_generic.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "avc_generic.h" +#include "serialize.h" + +AVCCommand::AVCCommand( opcode_t opcode ) + : m_ctype( eCT_Unknown ) + , m_subunit( 0xff ) + , m_opcode( opcode ) + , m_eResponse( eR_Unknown ) + , m_verbose( false ) +{ +} + +bool +AVCCommand::serialize( IOSSerialize& se ) +{ + se.write( m_ctype, "AVCCommand ctype" ); + se.write( m_subunit, "AVCCommand subunit" ); + se.write( m_opcode, "AVCCommand opcode" ); + return true; +} + +bool +AVCCommand::deserialize( IISDeserialize& de ) +{ + de.read( &m_ctype ); + de.read( &m_subunit ); + de.read( &m_opcode ); + return true; +} + +bool +AVCCommand::setCommandType( ECommandType commandType ) +{ + m_ctype = commandType; + m_commandType = commandType; + return true; +} + +AVCCommand::ECommandType +AVCCommand::getCommandType() +{ + return m_commandType; +} + +AVCCommand::EResponse +AVCCommand::getResponse() +{ + return m_eResponse; +} + +bool +AVCCommand::parseResponse( byte_t response ) +{ + m_eResponse = static_cast( response ); + return true; +} + +bool +AVCCommand::setSubunitType(ESubunitType subunitType) +{ + byte_t subT = subunitType; + + m_subunit = ( subT << 3 ) | ( m_subunit & 0x7 ); + return true; +} + +bool +AVCCommand::setSubunitId(subunit_id_t subunitId) +{ + m_subunit = ( subunitId & 0x7 ) | ( m_subunit & 0xf8 ); + return true; +} + +AVCCommand::ESubunitType +AVCCommand::getSubunitType() +{ + return static_cast( ( m_subunit >> 3 ) ); +} + +subunit_id_t +AVCCommand::getSubunitId() +{ + return m_subunit & 0x7; +} + +bool +AVCCommand::setVerbose( bool enable ) +{ + m_verbose = enable; + return true; +} + +bool +AVCCommand::isVerbose() +{ + return m_verbose; +} Index: /branches/libfreebob-1.4/freebob/tests/avc_definitions.h =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_definitions.h (revision 109) +++ /branches/libfreebob-1.4/freebob/tests/avc_definitions.h (revision 109) @@ -0,0 +1,74 @@ +/* avc_definitions.h + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#ifndef AVCDefinitions_h +#define AVCDefinitions_h + +#include +#include + +typedef byte_t ctype_t; +typedef byte_t subunit_t; +typedef byte_t opcode_t; +typedef byte_t plug_type_t; +typedef byte_t plug_id_t; +typedef byte_t reserved_t; +typedef byte_t function_block_type_t; +typedef byte_t function_block_id_t; +typedef byte_t plug_direction_t; +typedef byte_t plug_address_mode_t; +typedef byte_t status_t; +typedef byte_t number_of_channels_t; +typedef byte_t stream_format_t; +typedef byte_t sampling_frequency_t; +typedef byte_t rate_control_t; +typedef byte_t number_of_stream_format_infos_t; +typedef byte_t nr_of_plugs_t; +typedef byte_t subunit_id_t; +typedef byte_t subfunction_t; +typedef byte_t opcode_t; + +enum ESamplingFrequency { + eSF_22050Hz = 0x00, + eSF_24000Hz = 0x01, + eSF_32000Hz = 0x02, + eSF_44100Hz = 0x03, + eSF_48000Hz = 0x04, + eSF_88200Hz = 0x0A, + eSF_96000Hz = 0x05, + eSF_176400Hz = 0x06, + eSF_192000Hz = 0x07, + eSF_DontCare = 0x0F, +}; + +std::ostream& operator<<( std::ostream& stream, ESamplingFrequency freq ); + +#define AVC1394_SUBUNIT_AUDIO 1 +#define AVC1394_SUBUNIT_PRINTER 2 +#define AVC1394_SUBUNIT_CA 6 +#define AVC1394_SUBUNIT_PANEL 9 +#define AVC1394_SUBUNIT_BULLETIN_BOARD 0xA +#define AVC1394_SUBUNIT_CAMERA_STORAGE 0xB +#define AVC1394_SUBUNIT_MUSIC 0xC +#define AVC1394_SUBUNIT_RESERVED 0x1D + +#define AVC1394_SUBUNIT_ID_RESERVED 0x06 + +#endif // AVCDefinitions_h Index: /branches/libfreebob-1.4/freebob/tests/test-freebob-iso.c =================================================================== --- /branches/libfreebob-1.4/freebob/tests/test-freebob-iso.c (revision 92) +++ /branches/libfreebob-1.4/freebob/tests/test-freebob-iso.c (revision 92) @@ -0,0 +1,323 @@ +/* + * FreeBob Test Program + * Copyright (C) 2005 Pieter Palmers + * + * Timing code shamelessly copied from Mixxx source code + * (C) 2002 by Tue and Ken Haste Andersen + */ + +/* Based upon code from: + * libiec61883 - Linux IEEE 1394 streaming media library. + * Copyright (C) 2004 Kristian Hogsberg and Dan Dennedy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * ./test-freebob-iso -b 100 -i 10 -p 1024 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + #define QUATAFIRE_DEFAULT_SAMPLE_RATE 48000 + #define QUATAFIRE_OUT_DIMENSION 11 + #define QUATAFIRE_IN_DIMENSION 7 + #define QUATAFIRE_INPUT_TARGET_CHANNEL 1 + #define QUATAFIRE_MIDI_OUT_STREAM_POSITION 10 +#if __BYTE_ORDER == __BIG_ENDIAN + +struct iso_packet_header { + unsigned int data_length : 16; + unsigned int tag : 2; + unsigned int channel : 6; + unsigned int tcode : 4; + unsigned int sy : 4; +}; + +struct iec61883_packet { + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + unsigned char data[0]; +}; + +#elif __BYTE_ORDER == __LITTLE_ENDIAN + +struct iso_packet_header { + unsigned int data_length : 16; + unsigned int channel : 6; + unsigned int tag : 2; + unsigned int sy : 4; + unsigned int tcode : 4; +}; + +struct iec61883_packet { + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + unsigned char data[0]; +}; + +#else + +#error Unknown bitfield type + +#endif + +inline unsigned long currentTime2() { + struct timeval now; + gettimeofday(&now, NULL); + return now.tv_sec*1000+now.tv_usec/1000; +} + +static int g_done = 0; + +static void sighandler (int sig) +{ + g_done = 1; +} + +static enum raw1394_iso_disposition +iso_handler(raw1394handle_t handle, unsigned char *data, + unsigned int length, unsigned char channel, + unsigned char tag, unsigned char sy, unsigned int cycle, + unsigned int dropped) +{ + int ret; + static unsigned int counter = 0; + + struct iec61883_packet *packet = (struct iec61883_packet *) data; + + if (counter++>16) { + printf("FDF code = %X. SYT = %10d, DBS = %10d, DBC = %10d\n", packet->fdf,packet->syt,packet->dbs,packet->dbc); + counter=0; + } + /* write header */ + /* write(file, &length, sizeof(length)); + write(file, &channel, sizeof(channel)); + write(file, &tag, sizeof(tag)); + write(file, &sy, sizeof(sy)); + sy = 0; + write(file, &sy, sizeof(sy)); + + while (length) { + ret = write(file, data, length); + if (ret < 0) { + perror("data write"); + return RAW1394_ISO_ERROR; + } + + length -= ret; + data += ret; + } +*/ + return RAW1394_ISO_OK; +} + +//enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_DEFAULT; +enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_BUFFERFILL; +//enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_PACKET_PER_BUFFER; +//#define BUFFER 1000 +//#define IRQ 20 +//#define PACKET_MAX 8192 + +int main (int argc, char *argv[]) +{ + raw1394handle_t handle = raw1394_new_handle_on_port (0); + nodeid_t node = 0xffc0; + FILE *f = NULL; + int is_transmit = 0; + int node_specified = 0; + int i; + int channel; + int bandwidth = -1; + int heartbeat=0; + int iplug=-1; + int oplug=-1; + int irq=100; + int BUFFER=1000; + int PACKET_MAX=1024; + int retval; + + + int fd=raw1394_get_fd(handle); + struct pollfd pfd; + + u_int64_t listen_channels=0xFFFFFFFF; + unsigned long which_port; + + signal (SIGINT, sighandler); + signal (SIGPIPE, sighandler); + + for (i = 1; i < argc; i++) { + + if (strncmp (argv[i], "-h", 2) == 0 || + strncmp (argv[i], "--h", 3) == 0) + { + fprintf (stderr, + "usage: %s [[-r | -t] node-id]", argv[0]); + raw1394_destroy_handle (handle); + return 1; + } else if (strncmp (argv[i], "-t", 2) == 0) { + node |= atoi (argv[++i]); + is_transmit = 1; + node_specified = 1; + } else if (strncmp (argv[i], "-r", 2) == 0) { + node |= atoi (argv[++i]); + is_transmit = 0; + node_specified = 1; + } else if (strncmp (argv[i], "-b", 2) == 0) { + BUFFER = atoi (argv[++i]); + } else if (strncmp (argv[i], "-p", 2) == 0) { + PACKET_MAX = atoi (argv[++i]); + } else if (strncmp (argv[i], "-i", 2) == 0) { + irq = atoi (argv[++i]); + } else if (strncmp (argv[i], "-j", 2) == 0) { + iplug = atoi (argv[++i]); + } else if (strncmp (argv[i], "-k", 2) == 0) { + oplug = atoi (argv[++i]); + } else if (!node_specified) { + is_transmit = 1; + } + } + + if (handle) { + fprintf (stderr, "Init ISO receive handler...\n"); + + if (mode == RAW1394_DMA_DEFAULT) { + fprintf (stderr, " RAW1394_DMA_DEFAULT (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",BUFFER,PACKET_MAX, irq); + + raw1394_iso_multichannel_recv_init(handle, iso_handler, + BUFFER, PACKET_MAX, irq); /* >2048 makes rawiso stall! */ + raw1394_iso_recv_set_channel_mask(handle, listen_channels); + + } else { + fprintf (stderr, " other mode (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",BUFFER,PACKET_MAX, irq); + for (i = 0; i < 64; i++) { + if (!(listen_channels & 1ULL << i)) + continue; + raw1394_iso_recv_init(handle, iso_handler, BUFFER, PACKET_MAX, + i, mode, irq); + } + } + + fprintf (stderr, "Start ISO receive...\n"); + raw1394_iso_recv_start(handle, -1, -1, 0); + + fprintf (stderr, "Create CMP connection...\n"); + //channel = iec61883_cmp_connect (handle, raw1394_get_local_id (handle), &oplug, node, &iplug, &bandwidth); + channel = iec61883_cmp_connect (handle, node , &oplug, raw1394_get_local_id (handle), &iplug, &bandwidth); + if (channel > -1) { + //amdtp_receive (handle, f, channel); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + } + + fprintf (stderr, "Running raw1394_loop_iterate()...\n"); + + int packetcount=0; + +// polled receive loop + while (!g_done) { + int i=0; + while ((raw1394_loop_iterate(handle) == 0) && (i + +class IOSSerialize; +class IISDeserialize; + +class IBusData { +public: + virtual bool serialize( IOSSerialize& se ) = 0; + virtual bool deserialize( IISDeserialize& de ) = 0; + + virtual IBusData* clone() const = 0; +}; + +class AVCCommand +{ +public: + enum EResponse { + eR_Unknown = 0, + eR_NotImplemented = AVC1394_RESP_NOT_IMPLEMENTED, + eR_Accepted = AVC1394_RESP_ACCEPTED, + eR_Rejected = AVC1394_RESP_REJECTED, + eR_InTransition = AVC1394_RESP_IN_TRANSITION, + eR_Implemented = AVC1394_RESP_IMPLEMENTED, + eR_Changed = AVC1394_RESP_CHANGED, + eR_Interim = AVC1394_RESP_INTERIM, + }; + + enum ECommandType { + eCT_Control = AVC1394_CTYP_CONTROL, + eCT_Status = AVC1394_CTYP_STATUS, + eCT_SpecificInquiry = AVC1394_CTYP_SPECIFIC_INQUIRY, + eCT_Notify = AVC1394_CTYP_NOTIFY, + eCT_GeneralInquiry = AVC1394_CTYP_GENERAL_INQUIRY, + eCT_Unknown = 0xff, + }; + + enum ESubunitType { + eST_Monitor = AVC1394_SUBUNIT_VIDEO_MONITOR, + eST_Audio = AVC1394_SUBUNIT_AUDIO, + eST_Printer = AVC1394_SUBUNIT_PRINTER, + eST_Disc = AVC1394_SUBUNIT_DISC_RECORDER, + eST_VCR = AVC1394_SUBUNIT_VCR, + eST_Tuner = AVC1394_SUBUNIT_TUNER, + eST_CA = AVC1394_SUBUNIT_CA, + eST_Camera = AVC1394_SUBUNIT_VIDEO_CAMERA, + eST_Panel = AVC1394_SUBUNIT_PANEL, + eST_BulltinBoard = AVC1394_SUBUNIT_BULLETIN_BOARD, + eST_CameraStorage = AVC1394_SUBUNIT_CAMERA_STORAGE, + eST_Music = AVC1394_SUBUNIT_MUSIC, + eST_VendorUnique = AVC1394_SUBUNIT_VENDOR_UNIQUE, + eST_Reserved = AVC1394_SUBUNIT_RESERVED, + eST_Extended = AVC1394_SUBUNIT_EXTENDED, + eST_Unit = AVC1394_SUBUNIT_UNIT, + }; + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + + virtual bool setCommandType( ECommandType commandType ); + virtual bool fire(raw1394handle_t handle, + unsigned int node_id ) = 0; + + EResponse getResponse(); + + bool setSubunitType(ESubunitType subunitType); + bool setSubunitId(subunit_id_t subunitId); + + ESubunitType getSubunitType(); + subunit_id_t getSubunitId(); + + bool setVerbose( bool enable ); + bool isVerbose(); + + +protected: + AVCCommand( opcode_t opcode ); + virtual ~AVCCommand() {} + + bool parseResponse( byte_t response ); + ECommandType getCommandType(); + +private: + ctype_t m_ctype; + subunit_t m_subunit; + opcode_t m_opcode; + EResponse m_eResponse; + bool m_verbose; + ECommandType m_commandType; +}; + +#endif // AVCGeneric_h Index: /branches/libfreebob-1.4/freebob/tests/avc_plug_info.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_plug_info.cpp (revision 119) +++ /branches/libfreebob-1.4/freebob/tests/avc_plug_info.cpp (revision 119) @@ -0,0 +1,212 @@ +/* avc_plug_info.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "avc_plug_info.h" +#include "serialize.h" + +#include +#include + +using namespace std; + +PlugInfoCmd::PlugInfoCmd( ESubFunction eSubFunction ) + : AVCCommand( AVC1394_CMD_PLUG_INFO ) + , m_serialBusIsochronousInputPlugs( 0xff ) + , m_serialBusIsochronousOutputPlugs( 0xff ) + , m_externalInputPlugs( 0xff ) + , m_externalOutputPlugs( 0xff ) + , m_serialBusAsynchronousInputPlugs( 0xff ) + , m_serialBusAsynchronousOuputPlugs( 0xff ) + , m_destinationPlugs( 0xff ) + , m_sourcePlugs( 0xff ) + , m_subFunction( eSubFunction ) +{ +} + +PlugInfoCmd::~PlugInfoCmd() +{ +} + +bool +PlugInfoCmd::serialize( IOSSerialize& se ) +{ + byte_t reserved = 0xff; + + AVCCommand::serialize( se ); + se.write( m_subFunction, "PlugInfoCmd subFunction" ); + switch( getSubunitType() ) { + case eST_Unit: + switch( m_subFunction ) { + case eSF_SerialBusIsochronousAndExternalPlug: + se.write( m_serialBusIsochronousInputPlugs, "PlugInfoCmd serialBusIsochronousInputPlugs" ); + se.write( m_serialBusIsochronousOutputPlugs, "PlugInfoCmd serialBusIsochronousOutputPlugs" ); + se.write( m_externalInputPlugs, "PlugInfoCmd externalInputPlugs" ); + se.write( m_externalOutputPlugs, "PlugInfoCmd externalOutputPlugs" ); + break; + case eSF_SerialBusAsynchonousPlug: + se.write( m_serialBusAsynchronousInputPlugs, "PlugInfoCmd serialBusAsynchronousInputPlugs" ); + se.write( m_serialBusAsynchronousOuputPlugs, "PlugInfoCmd serialBusAsynchronousOuputPlugs" ); + se.write( reserved, "PlugInfoCmd" ); + se.write( reserved, "PlugInfoCmd" ); + break; + default: + cerr << "Could not serialize with subfucntion " << m_subFunction << endl; + return false; + } + break; + default: + se.write( m_destinationPlugs, "PlugInfoCmd destinationPlugs" ); + se.write( m_sourcePlugs, "PlugInfoCmd sourcePlugs" ); + se.write( reserved, "PlugInfoCmd" ); + se.write( reserved, "PlugInfoCmd" ); + } + return true; +} + +bool +PlugInfoCmd::deserialize( IISDeserialize& de ) +{ + byte_t reserved; + + AVCCommand::deserialize( de ); + de.read( &m_subFunction ); + switch ( getSubunitType() ) { + case eST_Unit: + switch ( m_subFunction ) { + case eSF_SerialBusIsochronousAndExternalPlug: + de.read( &m_serialBusIsochronousInputPlugs ); + de.read( &m_serialBusIsochronousOutputPlugs ); + de.read( &m_externalInputPlugs ); + de.read( &m_externalOutputPlugs ); + break; + case eSF_SerialBusAsynchonousPlug: + de.read( &m_serialBusAsynchronousInputPlugs ); + de.read( &m_serialBusAsynchronousOuputPlugs ); + de.read( &reserved ); + de.read( &reserved ); + break; + default: + cerr << "Could not deserialize with subfunction " << m_subFunction << endl; + return false; + } + break; + default: + de.read( &m_destinationPlugs ); + de.read( &m_sourcePlugs ); + de.read( &reserved ); + de.read( &reserved ); + } + return true; +} + +bool +PlugInfoCmd::fire( raw1394handle_t handle, + unsigned int node_id ) +{ + bool result = false; + + #define STREAM_FORMAT_REQUEST_SIZE 5 // XXX random length + union UPacket { + quadlet_t quadlet[STREAM_FORMAT_REQUEST_SIZE]; + unsigned char byte[STREAM_FORMAT_REQUEST_SIZE*4]; + }; + typedef union UPacket packet_t; + + packet_t req; + packet_t* resp; + + // initialize complete packet + memset( &req, 0xff, sizeof( req ) ); + + BufferSerialize se( req.byte, sizeof( req ) ); + if ( !serialize( se ) ) { + printf( "PlugInfoCmd::fire: Could not serialize\n" ); + return false; + } + + // reorder the bytes to the correct layout + for (int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i) { + req.quadlet[i] = ntohl( req.quadlet[i] ); + } + + if ( isVerbose() ) { + // debug output + puts("request:"); + for (int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i) { + printf(" %2d: 0x%08x\n", i, req.quadlet[i]); + } + } + + resp = reinterpret_cast ( avc1394_transaction_block( handle, node_id, req.quadlet, STREAM_FORMAT_REQUEST_SIZE, 1 ) ); + if ( resp ) { + if ( isVerbose() ) { + // debug output + puts("response:"); + for ( int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i ) { + printf( " %2d: 0x%08x\n", i, resp->quadlet[i] ); + } + } + + // reorder the bytes to the correct layout + for ( int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i ) { + resp->quadlet[i] = htonl( resp->quadlet[i] ); + } + + if ( isVerbose() ) { + // a more detailed debug output + printf( "\n" ); + printf( " idx type value\n" ); + printf( "-------------------------------------\n" ); + printf( " %02d ctype: 0x%02x\n", 0, resp->byte[0] ); + printf( " %02d subunit_type + subunit_id: 0x%02x\n", 1, resp->byte[1] ); + printf( " %02d opcode: 0x%02x\n", 2, resp->byte[2] ); + + for ( int i = 3; i < STREAM_FORMAT_REQUEST_SIZE * 4; ++i ) { + printf( " %02d operand %2d: 0x%02x\n", i, i-3, resp->byte[i] ); + } + } + + // parse output + parseResponse( resp->byte[0] ); + switch ( getResponse() ) + { + case eR_Implemented: + { + BufferDeserialize de( resp->byte, sizeof( req ) ); + deserialize( de ); + result = true; + } + break; + default: + printf( "unexpected response received (0x%x)\n", getResponse() ); + } + } else { + printf( "no response\n" ); + } + + return result; +} + +bool +PlugInfoCmd::setSubFunction( ESubFunction subFunction ) +{ + m_subFunction = subFunction; + return true; +} Index: /branches/libfreebob-1.4/freebob/tests/avc_extended_stream_format.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_extended_stream_format.cpp (revision 119) +++ /branches/libfreebob-1.4/freebob/tests/avc_extended_stream_format.cpp (revision 119) @@ -0,0 +1,593 @@ +/* avc_extended_stream_format.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "avc_extended_stream_format.h" +#include "serialize.h" + +#include + +UnitPlugAddress::UnitPlugAddress( EPlugType plugType, plug_type_t plugId ) + : m_plugType( plugType ) + , m_plugId( plugId ) + , m_reserved( 0xff ) +{ +} + +bool +UnitPlugAddress::serialize( IOSSerialize& se ) +{ + se.write( m_plugType, "UnitPlugAddress plugType" ); + se.write( m_plugId, "UnitPlugAddress plugId" ); + se.write( m_reserved, "UnitPlugAddress reserved" ); + return true; +} + +bool +UnitPlugAddress::deserialize( IISDeserialize& de ) +{ + de.read( &m_plugType ); + de.read( &m_plugId ); + de.read( &m_reserved ); + return true; +} + +UnitPlugAddress* +UnitPlugAddress::clone() const +{ + return new UnitPlugAddress( *this ); +} + +//////////////////////////////////////////////////////////// + +SubunitPlugAddress::SubunitPlugAddress( plug_id_t plugId ) + : m_plugId( plugId ) + , m_reserved0( 0xff ) + , m_reserved1( 0xff ) +{ +} + +bool +SubunitPlugAddress::serialize( IOSSerialize& se ) +{ + se.write( m_plugId, "SubunitPlugAddress plugId" ); + se.write( m_reserved0, "SubunitPlugAddress reserved0" ); + se.write( m_reserved1, "SubunitPlugAddress reserved1" ); + return true; +} + +bool +SubunitPlugAddress::deserialize( IISDeserialize& de ) +{ + de.read( &m_plugId ); + de.read( &m_reserved0 ); + de.read( &m_reserved1 ); + return true; +} + +SubunitPlugAddress* +SubunitPlugAddress::clone() const +{ + return new SubunitPlugAddress( *this ); +} + +//////////////////////////////////////////////////////////// + + +FunctionBlockPlugAddress::FunctionBlockPlugAddress( function_block_type_t functionBlockType, + function_block_id_t functionBlockId, + plug_id_t plugId ) + : m_functionBlockType( functionBlockType ) + , m_functionBlockId( functionBlockId ) + , m_plugId( plugId ) +{ +} + +bool +FunctionBlockPlugAddress::serialize( IOSSerialize& se ) +{ + se.write( m_functionBlockType, "FunctionBlockPlugAddress functionBlockType" ); + se.write( m_functionBlockId, "FunctionBlockPlugAddress functionBlockId" ); + se.write( m_plugId, "FunctionBlockPlugAddress plugId" ); + return true; +} + +bool +FunctionBlockPlugAddress::deserialize( IISDeserialize& de ) +{ + de.read( &m_functionBlockType ); + de.read( &m_functionBlockId ); + de.read( &m_plugId ); + return true; +} + +FunctionBlockPlugAddress* +FunctionBlockPlugAddress:: clone() const +{ + return new FunctionBlockPlugAddress( *this ); +} + +//////////////////////////////////////////////////////////// + +PlugAddress::PlugAddress( EPlugDirection plugDirection, + EPlugAddressMode plugAddressMode, + UnitPlugAddress& unitPlugAddress ) + : m_plugDirection( plugDirection ) + , m_addressMode( plugAddressMode ) + , m_plugAddressData( new UnitPlugAddress( unitPlugAddress ) ) +{ +} + +PlugAddress::PlugAddress( EPlugDirection plugDirection, + EPlugAddressMode plugAddressMode, + SubunitPlugAddress& subUnitPlugAddress ) + : m_plugDirection( plugDirection ) + , m_addressMode( plugAddressMode ) + , m_plugAddressData( new SubunitPlugAddress( subUnitPlugAddress ) ) +{ +} + +PlugAddress::PlugAddress( EPlugDirection plugDirection, + EPlugAddressMode plugAddressMode, + FunctionBlockPlugAddress& functionBlockPlugAddress ) + : m_plugDirection( plugDirection ) + , m_addressMode( plugAddressMode ) + , m_plugAddressData( new FunctionBlockPlugAddress( functionBlockPlugAddress ) ) +{ +} + +PlugAddress::PlugAddress( const PlugAddress& pa ) + : m_plugDirection( pa.m_plugDirection ) + , m_addressMode( pa.m_addressMode ) + , m_plugAddressData( dynamic_cast( pa.m_plugAddressData->clone() ) ) +{ +} + +PlugAddress::~PlugAddress() +{ + delete m_plugAddressData; + m_plugAddressData = 0; +} + +bool +PlugAddress::serialize( IOSSerialize& se ) +{ + se.write( m_plugDirection, "PlugAddress plugDirection" ); + se.write( m_addressMode, "PlugAddress addressMode" ); + return m_plugAddressData->serialize( se ); +} + +bool +PlugAddress::deserialize( IISDeserialize& de ) +{ + de.read( &m_plugDirection ); + de.read( &m_addressMode ); + return m_plugAddressData->deserialize( de ); +} + +PlugAddress* +PlugAddress::clone() const +{ + return new PlugAddress( *this ); +} + +//////////////////////////////////////////////////////////// + +StreamFormatInfo::StreamFormatInfo() + : IBusData() +{ +} + +bool +StreamFormatInfo::serialize( IOSSerialize& se ) +{ + se.write( m_numberOfChannels, "StreamFormatInfo numberOfChannels" ); + se.write( m_streamFormat, "StreamFormatInfo streamFormat" ); + return true; +} + +bool +StreamFormatInfo::deserialize( IISDeserialize& de ) +{ + de.read( &m_numberOfChannels ); + de.read( &m_streamFormat ); + return true; +} + +StreamFormatInfo* +StreamFormatInfo::clone() const +{ + return new StreamFormatInfo( *this ); +} + +//////////////////////////////////////////////////////////// + +FormatInformationStreamsSync::FormatInformationStreamsSync() + : FormatInformationStreams() + , m_reserved0( 0xff ) + , m_samplingFrequency( eSF_DontCare ) + , m_rateControl( eRC_DontCare ) + , m_reserved1( 0xff ) +{ +} + +bool +FormatInformationStreamsSync::serialize( IOSSerialize& se ) +{ + se.write( m_reserved0, "FormatInformationStreamsSync reserved" ); + + // we have to clobber some bits + byte_t operand = ( m_samplingFrequency << 4 ) | 0x0e; + if ( m_rateControl == eRC_DontCare) { + operand |= 0x1; + } + se.write( operand, "FormatInformationStreamsSync sampling frequency and rate control" ); + + se.write( m_reserved1, "FormatInformationStreamsSync reserved" ); + return true; +} + +bool +FormatInformationStreamsSync::deserialize( IISDeserialize& de ) +{ + de.read( &m_reserved0 ); + + byte_t operand; + de.read( &operand ); + m_samplingFrequency = operand >> 4; + m_rateControl = operand & 0x01; + + de.read( &m_reserved1 ); + return true; +} + +FormatInformationStreamsSync* +FormatInformationStreamsSync::clone() const +{ + return new FormatInformationStreamsSync( *this ); +} + +//////////////////////////////////////////////////////////// + +FormatInformationStreamsCompound::FormatInformationStreamsCompound() + : FormatInformationStreams() + , m_samplingFrequency( eSF_DontCare ) + , m_rateControl( eRC_DontCare ) + , m_numberOfStreamFormatInfos( 0 ) +{ +} + +FormatInformationStreamsCompound::~FormatInformationStreamsCompound() +{ + for ( StreamFormatInfoVector::iterator it = m_streamFormatInfos.begin(); + it != m_streamFormatInfos.end(); + ++it ) + { + delete *it; + } +} + +bool +FormatInformationStreamsCompound::serialize( IOSSerialize& se ) +{ + se.write( m_samplingFrequency, "FormatInformationStreamsCompound samplingFrequency" ); + se.write( m_rateControl, "FormatInformationStreamsCompound rateControl" ); + se.write( m_numberOfStreamFormatInfos, "FormatInformationStreamsCompound numberOfStreamFormatInfos" ); + for ( StreamFormatInfoVector::iterator it = m_streamFormatInfos.begin(); + it != m_streamFormatInfos.end(); + ++it ) + { + ( *it )->serialize( se ); + } + return true; +} + +bool +FormatInformationStreamsCompound::deserialize( IISDeserialize& de ) +{ + de.read( &m_samplingFrequency ); + de.read( &m_rateControl ); + de.read( &m_numberOfStreamFormatInfos ); + for ( int i = 0; i < m_numberOfStreamFormatInfos; ++i ) { + StreamFormatInfo* streamFormatInfo = new StreamFormatInfo; + if ( !streamFormatInfo->deserialize( de ) ) { + return false; + } + m_streamFormatInfos.push_back( streamFormatInfo ); + } + return true; +} + +FormatInformationStreamsCompound* +FormatInformationStreamsCompound::clone() const +{ + return new FormatInformationStreamsCompound( *this ); +} + +//////////////////////////////////////////////////////////// + +FormatInformation::FormatInformation() + : IBusData() + , m_root( eFHR_Invalid ) + , m_level1( eFHL1_AUDIOMUSIC_DONT_CARE ) + , m_level2( eFHL2_AM824_DONT_CARE ) + , m_streams( 0 ) +{ +} + +FormatInformation::~FormatInformation() +{ + delete m_streams; + m_streams = 0; +} + +bool +FormatInformation::serialize( IOSSerialize& se ) +{ + if ( m_root != eFHR_Invalid ) { + se.write( m_root, "FormatInformation hierarchy root" ); + if ( m_level1 != eFHL1_AUDIOMUSIC_DONT_CARE ) { + se.write( m_level1, "FormatInformation hierarchy level 1" ); + if ( m_level2 != eFHL2_AM824_DONT_CARE ) { + se.write( m_level2, "FormatInformation hierarchy level 2" ); + } + } + } + if ( m_streams ) { + return m_streams->serialize( se ); + } + return true; +} + +bool +FormatInformation::deserialize( IISDeserialize& de ) +{ + bool result = false; + + delete m_streams; + m_streams = 0; + + // this code just parses BeBoB replies. + de.read( &m_root ); + + // just parse an audio and music hierarchy + if ( m_root == eFHR_AudioMusic ) { + de.read( &m_level1 ); + + switch ( m_level1 ) { + case eFHL1_AUDIOMUSIC_AM824: + { + // note: compound streams don't have a second level + de.read( &m_level2 ); + + if (m_level2 == eFHL2_AM824_SYNC_STREAM ) { + m_streams = new FormatInformationStreamsSync(); + result = m_streams->deserialize( de ); + } else { + // anything but the sync stream workds currently. + printf( "could not parse format information. (format hierarchy level 2 not recognized)\n" ); + } + } + break; + case eFHL1_AUDIOMUSIC_AM824_COMPOUND: + { + m_streams = new FormatInformationStreamsCompound(); + result = m_streams->deserialize( de ); + } + break; + default: + printf( "could not parse format information. (format hierarchy level 1 not recognized)\n" ); + } + } + + return result; +} + +FormatInformation* +FormatInformation::clone() const +{ + return new FormatInformation( *this ); +} + +//////////////////////////////////////////////////////////// + +ExtendedStreamFormatCmd::ExtendedStreamFormatCmd( ESubFunction eSubFunction ) + : AVCCommand( AVC1394_STREAM_FORMAT_SUPPORT ) + , m_subFunction( eSubFunction ) + , m_status( eS_NotUsed ) + , m_indexInStreamFormat( 0 ) + , m_formatInformation( new FormatInformation ) +{ + UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0x00 ); + m_plugAddress = new PlugAddress( PlugAddress::ePD_Output, PlugAddress::ePAM_Unit, unitPlugAddress ); +} + +ExtendedStreamFormatCmd::~ExtendedStreamFormatCmd() +{ + delete m_plugAddress; + m_plugAddress = 0; + delete m_formatInformation; + m_formatInformation = 0; +} + +bool +ExtendedStreamFormatCmd::setPlugAddress( const PlugAddress& plugAddress ) +{ + delete m_plugAddress; + m_plugAddress = plugAddress.clone(); + return true; +} + +bool +ExtendedStreamFormatCmd::setIndexInStreamFormat( const int index ) +{ + m_indexInStreamFormat = index; + return true; +} + +bool +ExtendedStreamFormatCmd::serialize( IOSSerialize& se ) +{ + AVCCommand::serialize( se ); + se.write( m_subFunction, "ExtendedStreamFormatCmd subFunction" ); + m_plugAddress->serialize( se ); + se.write( m_status, "ExtendedStreamFormatCmd status" ); + if ( m_subFunction == eSF_ExtendedStreamFormatInformationCommandList ) { + se.write( m_indexInStreamFormat, "indexInStreamFormat" ); + } + m_formatInformation->serialize( se ); + return true; +} + +bool +ExtendedStreamFormatCmd::deserialize( IISDeserialize& de ) +{ + AVCCommand::deserialize( de ); + de.read( &m_subFunction ); + m_plugAddress->deserialize( de ); + de.read( &m_status ); + if ( m_subFunction == eSF_ExtendedStreamFormatInformationCommandList ) { + de.read( &m_indexInStreamFormat ); + } + m_formatInformation->deserialize( de ); + return true; +} + +bool +ExtendedStreamFormatCmd::fire( raw1394handle_t handle, + unsigned int node_id ) +{ + bool result = false; + + #define STREAM_FORMAT_REQUEST_SIZE 6 // XXX random length + union UPacket { + quadlet_t quadlet[STREAM_FORMAT_REQUEST_SIZE]; + unsigned char byte[STREAM_FORMAT_REQUEST_SIZE*4]; + }; + typedef union UPacket packet_t; + + packet_t req; + packet_t* resp; + + // initialize complete packet + memset( &req, 0xff, sizeof( req ) ); + + BufferSerialize se( req.byte, sizeof( req ) ); + if ( !serialize( se ) ) { + printf( "ExtendedStreamFormatCmd::fire: Could not serialize\n" ); + return false; + } + + // reorder the bytes to the correct layout + for (int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i) { + req.quadlet[i] = ntohl( req.quadlet[i] ); + } + + if ( isVerbose() ) { + // debug output + puts("request:"); + for (int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i) { + printf(" %2d: 0x%08x\n", i, req.quadlet[i]); + } + } + + resp = reinterpret_cast ( avc1394_transaction_block( handle, node_id, req.quadlet, STREAM_FORMAT_REQUEST_SIZE, 1 ) ); + if ( resp ) { + if ( isVerbose() ) { + // debug output + puts("response:"); + for ( int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i ) { + printf( " %2d: 0x%08x\n", i, resp->quadlet[i] ); + } + } + + // reorder the bytes to the correct layout + for ( int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i ) { + resp->quadlet[i] = htonl( resp->quadlet[i] ); + } + + if ( isVerbose() ) { + // a more detailed debug output + printf( "\n" ); + printf( " idx type value\n" ); + printf( "-------------------------------------\n" ); + printf( " %02d ctype: 0x%02x\n", 0, resp->byte[0] ); + printf( " %02d subunit_type + subunit_id: 0x%02x\n", 1, resp->byte[1] ); + printf( " %02d opcode: 0x%02x\n", 2, resp->byte[2] ); + + for ( int i = 3; i < STREAM_FORMAT_REQUEST_SIZE * 4; ++i ) { + printf( " %02d operand %2d: 0x%02x\n", i, i-3, resp->byte[i] ); + } + } + + // parse output + parseResponse( resp->byte[0] ); + switch ( getResponse() ) + { + case eR_Implemented: + { + BufferDeserialize de( resp->byte, sizeof( req ) ); + deserialize( de ); + result = true; + } + break; + case eR_Rejected: + if ( m_subFunction == eSF_ExtendedStreamFormatInformationCommandList ) { + if ( isVerbose() ) { + printf( "no futher stream formats defined\n" ); + } + result = true; + } else { + printf( "request rejected\n" ); + } + break; + default: + printf( "unexpected response received (0x%x)\n", getResponse() ); + } + } else { + printf( "no response\n" ); + } + + return result; +} + +status_t +ExtendedStreamFormatCmd::getStatus() +{ + return m_status; +} + +FormatInformation* +ExtendedStreamFormatCmd::getFormatInformation() +{ + return m_formatInformation; +} + +ExtendedStreamFormatCmd::index_in_stream_format_t +ExtendedStreamFormatCmd::getIndex() +{ + return m_indexInStreamFormat; +} + +bool +ExtendedStreamFormatCmd::setSubFunction( ESubFunction subFunction ) +{ + m_subFunction = subFunction; + return true; +} Index: /branches/libfreebob-1.4/freebob/tests/avc_plug_info.h =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_plug_info.h (revision 112) +++ /branches/libfreebob-1.4/freebob/tests/avc_plug_info.h (revision 112) @@ -0,0 +1,72 @@ +/* avc_plug_info.h + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#ifndef AVCPlugInfo_h +#define AVCPlugInfo_h + +#include "avc_generic.h" + +#include + +#define AVC1394_PLUG_INFO_SUBFUNCTION_SERIAL_BUS_ISOCHRONOUS_AND_EXTERNAL_PLUG 0x00 +#define AVC1394_PLUG_INFO_SUBFUNCTION_SERIAL_BUS_ASYNCHRONOUS_PLUG 0x01 +#define AVC1394_PLUG_INFO_SUBFUNCTION_SERIAL_BUS_GENERIC_BUS_PLUG_BLUETOOTH 0x40 +#define AVC1394_PLUG_INFO_SUBFUNCTION_SERIAL_BUS_NOT_USED 0xFF + + + +class PlugInfoCmd: public AVCCommand +{ +public: + enum ESubFunction { + eSF_SerialBusIsochronousAndExternalPlug = AVC1394_PLUG_INFO_SUBFUNCTION_SERIAL_BUS_ISOCHRONOUS_AND_EXTERNAL_PLUG, + eSF_SerialBusAsynchonousPlug = AVC1394_PLUG_INFO_SUBFUNCTION_SERIAL_BUS_ASYNCHRONOUS_PLUG, + eSF_SerialBusPlug = AVC1394_PLUG_INFO_SUBFUNCTION_SERIAL_BUS_GENERIC_BUS_PLUG_BLUETOOTH, + eSF_NotUsed = AVC1394_PLUG_INFO_SUBFUNCTION_SERIAL_BUS_NOT_USED, + }; + + PlugInfoCmd( ESubFunction eSubFunction = eSF_SerialBusIsochronousAndExternalPlug ); + virtual ~PlugInfoCmd(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + + virtual bool fire( raw1394handle_t handle, + unsigned int node_id ); + + + nr_of_plugs_t m_serialBusIsochronousInputPlugs; + nr_of_plugs_t m_serialBusIsochronousOutputPlugs; + nr_of_plugs_t m_externalInputPlugs; + nr_of_plugs_t m_externalOutputPlugs; + nr_of_plugs_t m_serialBusAsynchronousInputPlugs; + nr_of_plugs_t m_serialBusAsynchronousOuputPlugs; + nr_of_plugs_t m_destinationPlugs; + nr_of_plugs_t m_sourcePlugs; + + bool setSubFunction( ESubFunction subFunction ); + +protected: + subfunction_t m_subFunction; + +}; + + +#endif // AVCPlugInfo_h Index: /branches/libfreebob-1.4/freebob/tests/sync_mode.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/sync_mode.cpp (revision 119) +++ /branches/libfreebob-1.4/freebob/tests/sync_mode.cpp (revision 119) @@ -0,0 +1,666 @@ +/* sync_mode.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "avc_extended_stream_format.h" +#include "avc_plug_info.h" +#include "avc_signal_source.h" +#include "serialize.h" +#include "convert.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; + +//////////////////////////////////////////////// +// arg parsing +//////////////////////////////////////////////// +const char *argp_program_version = "sync_mode 0.1"; +const char *argp_program_bug_address = ""; +static char doc[] = "sync_mode -- get/set sync mode for FreeBob"; +static char args_doc[] = "NODE_ID"; +static struct argp_option options[] = { + {"verbose", 'v', 0, 0, "Produce verbose output" }, + {"test", 't', 0, 0, "Do tests instead get/set action" }, + {"sync", 's', "SYNC_MODE", 0, "Set sync mode" }, + {"port", 'p', "PORT", 0, "Set port" }, + { 0 } +}; + +struct arguments +{ + arguments() + : verbose( false ) + , test( false ) + , sync_mode_id( -1 ) + , port( 0 ) + { + args[0] = 0; + } + + char* args[1]; + bool verbose; + bool test; + int sync_mode_id; + int port; +} arguments; + +// Parse a single option. +static error_t +parse_opt( int key, char* arg, struct argp_state* state ) +{ + // Get the input argument from `argp_parse', which we + // know is a pointer to our arguments structure. + struct arguments* arguments = ( struct arguments* ) state->input; + + char* tail; + switch (key) { + case 'v': + arguments->verbose = true; + break; + case 't': + arguments->test = true; + break; + case 's': + arguments->sync_mode_id = strtol(arg, &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return errno; + } + break; + case 'p': + errno = 0; + arguments->port = strtol(arg, &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return errno; + } + break; + case ARGP_KEY_ARG: + if (state->arg_num >= 1) { + // Too many arguments. + argp_usage (state); + } + arguments->args[state->arg_num] = arg; + break; + case ARGP_KEY_END: + if (state->arg_num < 1) { + // Not enough arguments. + argp_usage (state); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { options, parse_opt, args_doc, doc }; + +//////////////////////////////////////// +// Test application +//////////////////////////////////////// +bool +doTest( raw1394handle_t handle, int node_id ) +{ + /* + ExtendedStreamFormatCmd extendedStreamFormatCmd; + UnitPlugAddress unitPlugAddress( 0x00, 0x00 ); + extendedStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::eM_Subunit, + PlugAddress::ePD_Input, + unitPlugAddress ) ); + extendedStreamFormatCmd.setVerbose( arguments.verbose ); + extendedStreamFormatCmd.setCommandType( AVCCommand::eCT_Status ); + extendedStreamFormatCmd.fire( handle, node_id ); + + PlugInfoCmd plugInfoCmd; + plugInfoCmd.setVerbose( arguments.verbose ); + plugInfoCmd.setCommandType( AVCCommand::eCT_Status ); + if ( plugInfoCmd.fire( handle, node_id ) ) { + CoutSerializer se; + plugInfoCmd.serialize( se ); + } + + plugInfoCmd.setSubFunction( PlugInfoCmd::eSF_SerialBusAsynchonousPlug ); + plugInfoCmd.setCommandType( AVCCommand::eCT_Status ); + if ( plugInfoCmd.fire( handle, node_id ) ) { + CoutSerializer se; + plugInfoCmd.serialize( se ); + } + */ + + SignalSourceCmd signalSourceCmd; + SignalUnitAddress dest; + dest.m_plugId = 0x00; + signalSourceCmd.setSignalDestination( dest ); + signalSourceCmd.setCommandType( AVCCommand::eCT_Status ); + signalSourceCmd.setVerbose( arguments.verbose ); + + CoutSerializer se; + signalSourceCmd.serialize( se ); + + if ( signalSourceCmd.fire( handle, node_id ) ) { + signalSourceCmd.serialize( se ); + } + + return true; +} + +//////////////////////////////////////// +// Main application +//////////////////////////////////////// + +struct PlugInfo { + PlugInfo() + : m_name( "" ) + , m_subunitType( AVCCommand::eST_Reserved ) + , m_subunitId( 0xff ) + , m_plugId( 0xff ) + {} + PlugInfo( string name, AVCCommand::ESubunitType subunitType, byte_t subunitId, byte_t plugId ) + : m_name( name ) + , m_subunitType( subunitType ) + , m_subunitId( subunitId ) + , m_plugId( plugId ) + {} + + bool operator == ( const PlugInfo& rhs ) const + { + return ( ( m_subunitType == rhs.m_subunitType ) + && ( m_subunitId == rhs.m_subunitId ) + && ( m_plugId == rhs.m_plugId ) ); + } + + string m_name; + AVCCommand::ESubunitType m_subunitType; + byte_t m_subunitId; + byte_t m_plugId; +}; + +ostream& operator << ( ostream& stream, PlugInfo& info ) +{ + return stream << info.m_name + << ", subunitType " << info.m_subunitType + << ", subunitId " << ( int )info.m_subunitId + << ", plugId " << ( int )info.m_plugId; +} + +struct SyncConnectionInfo { + SyncConnectionInfo( string name, int id, PlugInfo sourcePlug, PlugInfo destinationPlug ) + : m_name( name ) + , m_id( id ) + , m_sourcePlug( sourcePlug ) + , m_destinationPlug( destinationPlug ) + {} + + string m_name; + int m_id; + PlugInfo m_sourcePlug; + PlugInfo m_destinationPlug; +}; +typedef vector SyncConnectionInfos; + + + +static +bool inquireConnection( raw1394handle_t handle, + int node_id, + SyncConnectionInfos& syncConnectionInfos, + const PlugInfo& sourcePlug, + const PlugInfo& destPlug, + const string connectionName ) +{ + SignalSourceCmd signalSourceCmd; + signalSourceCmd.setSubunitType( AVCCommand::eST_Unit ); + signalSourceCmd.setCommandType( AVCCommand::eCT_SpecificInquiry ); + signalSourceCmd.setVerbose( arguments.verbose ); + + SignalSubunitAddress signalSubunitAddressSource; + signalSubunitAddressSource.m_subunitType = sourcePlug.m_subunitType; + signalSubunitAddressSource.m_subunitId = sourcePlug.m_subunitId; + signalSubunitAddressSource.m_plugId = sourcePlug.m_plugId; + signalSourceCmd.setSignalSource( signalSubunitAddressSource ); + + SignalSubunitAddress signalSubunitAddressDestination; + signalSubunitAddressDestination.m_subunitType = destPlug.m_subunitType; + signalSubunitAddressDestination.m_subunitId = destPlug.m_subunitId; + signalSubunitAddressDestination.m_plugId = destPlug.m_plugId; + signalSourceCmd.setSignalDestination( signalSubunitAddressDestination ); + + if ( signalSourceCmd.fire( handle, node_id ) ) { + if ( signalSourceCmd.getResponse() == AVCCommand::eR_Implemented ) { + syncConnectionInfos.push_back( SyncConnectionInfo( connectionName, syncConnectionInfos.size(), sourcePlug, destPlug ) ); + } + } else { + return false; + } + + return true; +} + + +static SyncConnectionInfo* +getSyncConnectionInfo( SyncConnectionInfos& syncConnectionInfos, + PlugInfo& sourcePlug ) +{ + SyncConnectionInfo* info = 0; + for ( SyncConnectionInfos::iterator it = syncConnectionInfos.begin(); + it != syncConnectionInfos.end(); + ++it ) + { + if ( it->m_sourcePlug == sourcePlug ) { + info = &( *it ); + } + + } + return info; +} + +static bool +findSyncPlugs( raw1394handle_t handle, int node_id, PlugInfo& syncInputPlug, PlugInfo& syncOutputPlug ) +{ + // First we have to find the music subunit sync input plug (address) + PlugInfoCmd plugInfoCmd; + plugInfoCmd.setCommandType( AVCCommand::eCT_Status ); + plugInfoCmd.setSubunitType( AVCCommand::eST_Music ); + plugInfoCmd.setSubunitId( 0x00 ); + + // find input sync plug + if ( plugInfoCmd.fire( handle, node_id ) ) { + for ( int plugIdx = 0; + plugIdx < plugInfoCmd.m_destinationPlugs; + ++plugIdx ) + { + ExtendedStreamFormatCmd extendedStreamFormatCmd; + + SubunitPlugAddress subunitPlugAddress( plugIdx ); + extendedStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input, + PlugAddress::ePAM_Subunit, + subunitPlugAddress ) ); + extendedStreamFormatCmd.setSubunitType( AVCCommand::eST_Music ); + extendedStreamFormatCmd.setSubunitId( 0x00 ); + extendedStreamFormatCmd.setCommandType( AVCCommand::eCT_Status ); + + if ( extendedStreamFormatCmd.fire( handle, node_id ) ) { + FormatInformation* formatInformation = extendedStreamFormatCmd.getFormatInformation(); + if ( formatInformation + && ( formatInformation->m_root == FormatInformation::eFHR_AudioMusic ) + && ( formatInformation->m_level1 == FormatInformation::eFHL1_AUDIOMUSIC_AM824 ) + && ( formatInformation->m_level2 == FormatInformation::eFHL2_AM824_SYNC_STREAM ) ) + { + syncInputPlug.m_name = "sync input plug"; + syncInputPlug.m_subunitType = AVCCommand::eST_Music; + syncInputPlug.m_subunitId = 0x00; + syncInputPlug.m_plugId = plugIdx; + } + } + } + + // find output sync plug + for ( int plugIdx = 0; + plugIdx < plugInfoCmd.m_sourcePlugs; + ++plugIdx ) + { + ExtendedStreamFormatCmd extendedStreamFormatCmd; + + SubunitPlugAddress subunitPlugAddress( plugIdx ); + extendedStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Output, + PlugAddress::ePAM_Subunit, + subunitPlugAddress ) ); + extendedStreamFormatCmd.setSubunitType( AVCCommand::eST_Music ); + extendedStreamFormatCmd.setSubunitId( 0x00 ); + extendedStreamFormatCmd.setCommandType( AVCCommand::eCT_Status ); + + if ( extendedStreamFormatCmd.fire( handle, node_id ) ) { + FormatInformation* formatInformation = extendedStreamFormatCmd.getFormatInformation(); + if ( formatInformation + && ( formatInformation->m_root == FormatInformation::eFHR_AudioMusic ) + && ( formatInformation->m_level1 == FormatInformation::eFHL1_AUDIOMUSIC_AM824 ) + && ( formatInformation->m_level2 == FormatInformation::eFHL2_AM824_SYNC_STREAM ) ) + { + syncOutputPlug.m_name = "sync output plug"; + syncOutputPlug.m_subunitType = AVCCommand::eST_Music; + syncOutputPlug.m_subunitId = 0x00; + syncOutputPlug.m_plugId = plugIdx; + } + } + } + } + if ( arguments.verbose ) { + cout << syncInputPlug << endl; + cout << syncOutputPlug << endl; + } + + return true; +} + +static +bool +findSupportedConnections( raw1394handle_t handle, + int node_id, + PlugInfo& syncInputPlug, + PlugInfo& syncOutputPlug, + SyncConnectionInfos& syncConnectionInfos ) +{ + // - Music subunit sync output plug = internal sync (CSP) + if ( !inquireConnection( handle, + node_id, + syncConnectionInfos, + syncOutputPlug, + syncInputPlug, + "internal (CSP)" ) ) + { + return false; + } + + // - Unit input plug 0 = SYT match + PlugInfo iPCR0( "iPCR[0]", AVCCommand::eST_Unit, 0xff, 0x00 ); + if ( !inquireConnection( handle, + node_id, + syncConnectionInfos, + iPCR0, + syncInputPlug, + "SYT match" ) ) + { + return false; + } + + // - Unit input plut 1 = sync stream + PlugInfo iPCR1( "iPCR[1]", AVCCommand::eST_Unit, 0xff, 0x01 ); + if ( !inquireConnection( handle, + node_id, + syncConnectionInfos, + iPCR1, + syncInputPlug, + "sync stream" ) ) + { + return false; + } + + // Find out how many external input plugs exits. + // Every one of them is possible a sync source + { + PlugInfoCmd plugInfoCmd; + plugInfoCmd.setCommandType( AVCCommand::eCT_Status ); + + if ( plugInfoCmd.fire( handle, node_id ) ) { + for ( int plugIdx = 0; + plugIdx < plugInfoCmd.m_externalInputPlugs; + ++plugIdx ) + { + // If we want to know what plug it is we have to + // parse the descriptor which is a overkill ATM. + // Let's keep it simple. + string plugName = "external plug " + stringify( plugIdx ); + PlugInfo externalPlug( plugName, + AVCCommand::eST_Unit, + 0xff, + 0x80 + plugIdx ); + if ( !inquireConnection( handle, + node_id, + syncConnectionInfos, + externalPlug, + syncInputPlug, + plugName) ) + { + return false; + } + } + } else { + return false; + } + } + return true; +} + +static +bool +setCurrentActive( raw1394handle_t handle, + int node_id, + PlugInfo& syncInputPlug, + SyncConnectionInfos& syncConnectionInfos, + int id ) +{ + SyncConnectionInfo* info = 0; + + for ( SyncConnectionInfos::iterator it = syncConnectionInfos.begin(); + it != syncConnectionInfos.end(); + ++it ) + { + if ( it->m_id == id ) { + info = &( *it ); + break; + } + } + + bool result = false; + if ( info ) { + SignalSourceCmd signalSourceCmd; + signalSourceCmd.setSubunitType( AVCCommand::eST_Unit ); + signalSourceCmd.setCommandType( AVCCommand::eCT_Control ); + signalSourceCmd.setVerbose( arguments.verbose ); + + if ( info->m_sourcePlug.m_subunitType == AVCCommand::eST_Unit ) { + SignalUnitAddress signalUnitAddress; + signalUnitAddress.m_plugId = info->m_sourcePlug.m_plugId; + signalSourceCmd.setSignalSource( signalUnitAddress ); + } else { + SignalSubunitAddress signalSubunitAddress; + signalSubunitAddress.m_subunitType = info->m_sourcePlug.m_subunitType; + signalSubunitAddress.m_subunitId = info->m_sourcePlug.m_subunitId; + signalSubunitAddress.m_plugId = info->m_sourcePlug.m_plugId; + signalSourceCmd.setSignalSource( signalSubunitAddress ); + } + + SignalSubunitAddress signalSubunitAddressDestination; + signalSubunitAddressDestination.m_subunitType = syncInputPlug.m_subunitType; + signalSubunitAddressDestination.m_subunitId = syncInputPlug.m_subunitId; + signalSubunitAddressDestination.m_plugId = syncInputPlug.m_plugId; + signalSourceCmd.setSignalDestination( signalSubunitAddressDestination ); + + if ( signalSourceCmd.fire( handle, node_id ) ) { + switch ( signalSourceCmd.getResponse() ) + { + case AVCCommand::eR_Accepted: + cout << endl << " -> new sync mode accepted" << endl; + result = true; + break; + case AVCCommand::eR_Rejected: + cout << endl << " -> new sync mode rejected" << endl; + result = true; + break; + default: + cerr << "unexpected response" << endl; + result = false; + } + } else { + cerr << "no response" << endl; + result = false; + } + } else { + cerr << "no sync method found for " << id << endl; + result = false; + } + + return result; +} + +static +bool printSupportedModes( raw1394handle_t handle, + int node_id, + SyncConnectionInfos& syncConnectionInfos ) +{ + cout << "Supported sync modes:" << endl; + for ( SyncConnectionInfos::iterator it = syncConnectionInfos.begin(); + it != syncConnectionInfos.end(); + ++it ) + { + cout << " (" << it->m_id << ") " << it->m_name << endl; + } + return true; +} + +static bool +printCurrentActive( raw1394handle_t handle, + int node_id, + SyncConnectionInfos& syncConnectionInfos, + PlugInfo& syncInputPlug ) +{ + SignalSourceCmd signalSourceCmd; + signalSourceCmd.setSubunitType( AVCCommand::eST_Unit ); + signalSourceCmd.setCommandType( AVCCommand::eCT_Status ); + signalSourceCmd.setVerbose( arguments.verbose ); + + SignalSubunitAddress signalSubunitAddressSource; + signalSubunitAddressSource.m_subunitType = 0xff; + signalSubunitAddressSource.m_subunitId = 0xff; + signalSubunitAddressSource.m_plugId = 0xff; + signalSourceCmd.setSignalSource( signalSubunitAddressSource ); + + SignalSubunitAddress signalSubunitAddressDestination; + signalSubunitAddressDestination.m_subunitType = syncInputPlug.m_subunitType; + signalSubunitAddressDestination.m_subunitId = syncInputPlug.m_subunitId; + signalSubunitAddressDestination.m_plugId = syncInputPlug.m_plugId; + signalSourceCmd.setSignalDestination( signalSubunitAddressDestination ); + + if ( signalSourceCmd.fire( handle, node_id ) ) { + if ( signalSourceCmd.getResponse() == AVCCommand::eR_Implemented ) { + cout << endl << "Currently activated mode:" << endl; + + SignalUnitAddress* signalUnitAddress = 0; + try { + signalUnitAddress = dynamic_cast( signalSourceCmd.getSignalSource() ); + } catch ( bad_cast ) { } + + SignalSubunitAddress* signalSubunitAddress = 0; + try { + signalSubunitAddress = dynamic_cast( signalSourceCmd.getSignalSource() ); + } catch ( bad_cast ) { } + + PlugInfo sourcePlug; + if ( signalUnitAddress ) { + sourcePlug.m_subunitType = AVCCommand::eST_Unit; + sourcePlug.m_subunitId = 0xff; + sourcePlug.m_plugId = signalUnitAddress->m_plugId; + } else if ( signalSubunitAddress ) { + sourcePlug.m_subunitType = static_cast( signalSubunitAddress->m_subunitType ); + sourcePlug.m_subunitId = signalSubunitAddress->m_subunitId; + sourcePlug.m_plugId = signalSubunitAddress->m_plugId; + } + + SyncConnectionInfo* info = getSyncConnectionInfo( syncConnectionInfos, sourcePlug ); + if ( info ) { + cout << " (" << info->m_id << ") " << info->m_name << endl; + } + } + } else { + return false; + } + + return true; +} + +bool +doApp( raw1394handle_t handle, int node_id, int sync_mode_id ) +{ + // Following sync sources always exists: + // - Music subunit sync output plug = internal sync (CSP) + // - Unit input plug 0 = SYT match + // - Unit input plut 1 = sync stream + + // + // Following sync sources are device specific: + // - All unit external input plugs which have a sync information (WS, SPDIF, ...) + + PlugInfo syncInputPlug; + PlugInfo syncOutputPlug; + SyncConnectionInfos syncConnectionInfos; + + if ( !findSyncPlugs( handle, node_id, syncInputPlug, syncOutputPlug ) ) { + cerr << "Could not discover sync plugs" << endl; + return false; + } + + if ( !findSupportedConnections( handle, node_id, syncInputPlug, syncOutputPlug, syncConnectionInfos ) ) { + cerr << "Could not find supported connections" << endl; + return false; + } + + bool result = false; + printSupportedModes( handle, node_id, syncConnectionInfos ); + if ( sync_mode_id != -1 ) { + if ( !setCurrentActive( handle, node_id, syncInputPlug, syncConnectionInfos, sync_mode_id ) ) { + cerr << "Could not set new sync mode" << endl; + } else { + result = true; + } + } + printCurrentActive( handle, node_id, syncConnectionInfos, syncInputPlug ); + + return result; +} + +int +main(int argc, char **argv) +{ + // arg parsing + argp_parse (&argp, argc, argv, 0, 0, &arguments); + + errno = 0; + char* tail; + int node_id = strtol(arguments.args[0], &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return -1; + } + + // create raw1394handle + raw1394handle_t handle; + handle = raw1394_new_handle (); + if (!handle) { + if (!errno) { + perror("lib1394raw not compatable\n"); + } else { + fprintf(stderr, "Could not get 1394 handle"); + fprintf(stderr, "Is ieee1394, driver, and raw1394 loaded?\n"); + } + return -1; + } + + if (raw1394_set_port(handle, arguments.port) < 0) { + fprintf(stderr, "Could not set port"); + raw1394_destroy_handle (handle); + return -1; + } + + if ( arguments.test ) { + doTest( handle, node_id ); + } else { + doApp( handle, node_id, arguments.sync_mode_id ); + } + + raw1394_destroy_handle( handle ); + + return 0; +} Index: /branches/libfreebob-1.4/freebob/tests/test-freebob-audio.c =================================================================== --- /branches/libfreebob-1.4/freebob/tests/test-freebob-audio.c (revision 81) +++ /branches/libfreebob-1.4/freebob/tests/test-freebob-audio.c (revision 81) @@ -0,0 +1,336 @@ +/* + * FreeBob Test Program + * Copyright (C) 2005 Pieter Palmers + * + * Timing code shamelessly copied from Mixxx source code + * (C) 2002 by Tue and Ken Haste Andersen + */ + +/* Based upon code from: + * libiec61883 - Linux IEEE 1394 streaming media library. + * Copyright (C) 2004 Kristian Hogsberg and Dan Dennedy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * To receive a stream (number is hardcoded by QUATAFIRE_INPUT_TARGET_CHANNEL) from the device at node 0 + * and play it out through /dev/dsp using sox play + * + * ./test-freebob-audio -r 0 - | play -r 48000 -t raw -s w -f s -c 1 - + * + */ + +/* To play a file on all outputs of the device at node 0 + * + * sox test.wav -r 48000 -t raw -s -w -c 1 - | ./test-freebob-audio -t 0 - + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + + #define QUATAFIRE_DEFAULT_SAMPLE_RATE 48000 + #define QUATAFIRE_OUT_DIMENSION 11 + #define QUATAFIRE_IN_DIMENSION 7 + #define QUATAFIRE_INPUT_TARGET_CHANNEL 1 + #define QUATAFIRE_MIDI_OUT_STREAM_POSITION 10 + +inline unsigned long currentTime2() { + struct timeval now; + gettimeofday(&now, NULL); + return now.tv_sec*1000+now.tv_usec/1000; +} + +static int g_done = 0; + +static void sighandler (int sig) +{ + g_done = 1; +} + +int fill_packet(iec61883_amdtp_t amdtp, char *data, int nevents, unsigned int dbc, + unsigned int dropped, void *callback_data) +{ + FILE *fp = (FILE *) callback_data; + + static int total_packets = 0; + + static int prev_total_packets=0; + static unsigned long prevtime=0; + float packets_per_second; + unsigned long thistime=currentTime2(); + + int i; + int j; + char *current_pos=data; + quadlet_t test=0; + short int sample; + + for (i=0; i < nevents; ++i) { + current_pos=data+i*QUATAFIRE_OUT_DIMENSION*4; + + // read in the sample from the file + if (fread((char *)(&sample), 2, 1, fp) != 1) + return -1; + + // make it 24 bit + test = 0x40 << 24 | sample<<8; + + // copy to all channels + for (j=0; j>8; + + if (fwrite(&value, 2, 1, f) != 1) { + return -1; + } + } + + total_packets++; + if ((total_packets & 0xfff) == 0) { + packets_per_second = (total_packets-prev_total_packets)/((float)(thistime-prevtime))*1000.0; + fprintf (stderr, "\r%10d packets (%5.2f packets/sec, %5d dropped, %d samples in last packet, packet dimension=%d)", total_packets, packets_per_second, dropped, nsamples, dimension); + fflush (stderr); + prevtime=thistime; + prev_total_packets=total_packets; + } + return 0; +} + +static void amdtp_receive( raw1394handle_t handle, FILE *f, int channel) +{ + iec61883_amdtp_t amdtp = iec61883_amdtp_recv_init (handle, read_packet, (void *)f ); + + if ( amdtp && iec61883_amdtp_recv_start (amdtp, channel) == 0) + { + int fd = raw1394_get_fd (handle); + struct timeval tv; + fd_set rfds; + int result = 0; + + signal (SIGINT, sighandler); + signal (SIGPIPE, sighandler); + fprintf (stderr, "Starting to receive\n"); + + do { + FD_ZERO (&rfds); + FD_SET (fd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 20000; + + if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0) + result = raw1394_loop_iterate (handle); + + } while (g_done == 0 && result == 0); + + fprintf (stderr, "\ndone.\n"); + } + iec61883_amdtp_close (amdtp); +} + +static void amdtp_transmit( raw1394handle_t handle, FILE *f, int channel) +{ + iec61883_amdtp_t amdtp; + + amdtp = iec61883_amdtp_xmit_init (handle, + 48000, + IEC61883_AMDTP_FORMAT_RAW, + IEC61883_AMDTP_INPUT_LE24, + IEC61883_MODE_BLOCKING_EMPTY, + QUATAFIRE_OUT_DIMENSION, + fill_packet, (void *)f ); + + if (amdtp && iec61883_amdtp_xmit_start (amdtp, channel) == 0) + { + int fd = raw1394_get_fd (handle); + struct timeval tv; + fd_set rfds; + int result = 0; + + signal (SIGINT, sighandler); + signal (SIGPIPE, sighandler); + fprintf (stderr, "Starting to transmit\n"); + + do { + FD_ZERO (&rfds); + FD_SET (fd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 20000; + + if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0) + result = raw1394_loop_iterate (handle); + + } while (g_done == 0 && result == 0); + + fprintf (stderr, "\ndone.\n"); + } + iec61883_amdtp_close (amdtp); +} + +int main (int argc, char *argv[]) +{ + raw1394handle_t handle = raw1394_new_handle_on_port (0); + nodeid_t node = 0xffc0; + FILE *f = NULL; + int is_transmit = 0; + int node_specified = 0; + int i; + int channel; + int bandwidth = -1; + + int iplug=-1; + int oplug=-1; + + for (i = 1; i < argc; i++) { + + if (strncmp (argv[i], "-h", 2) == 0 || + strncmp (argv[i], "--h", 3) == 0) + { + fprintf (stderr, + "usage: %s [[-r | -t] node-id] [- | file]\n" + " All audio data must be signed 16bit 48KHz stereo PCM\n" + " Use - to transmit raw PCM from stdin, or\n" + " supply a filename to to transmit from a raw PCM file.\n" + " Otherwise, capture raw PCM to stdout.\n", argv[0]); + raw1394_destroy_handle (handle); + return 1; + } else if (strncmp (argv[i], "-t", 2) == 0) { + node |= atoi (argv[++i]); + is_transmit = 1; + node_specified = 1; + } else if (strncmp (argv[i], "-r", 2) == 0) { + node |= atoi (argv[++i]); + is_transmit = 0; + node_specified = 1; + } else if (strcmp (argv[i], "-") != 0) { + if (node_specified && !is_transmit) + f = fopen (argv[i], "wb"); + else { + f = fopen (argv[i], "rb"); + is_transmit = 1; + } + } else if (!node_specified) { + is_transmit = 1; + } + } + + if (handle) { + if (is_transmit) { + if (f == NULL) + f = stdin; + if (node_specified) { + channel = iec61883_cmp_connect (handle, + raw1394_get_local_id (handle), &oplug, node, &iplug, &bandwidth); + if (channel > -1) { + amdtp_transmit (handle, f, channel); + iec61883_cmp_disconnect (handle, + raw1394_get_local_id (handle), oplug, node, iplug, channel, bandwidth); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + amdtp_transmit (handle, f, 63); + } + } else { + amdtp_transmit (handle, f, 63); + } + if (f != stdin) + fclose (f); + } else { + if (f == NULL) + f = stdout; + if (node_specified) { + channel = iec61883_cmp_connect (handle, node, &oplug, + raw1394_get_local_id (handle), &iplug, &bandwidth); + if (channel > -1) { + amdtp_receive (handle, f, channel); + iec61883_cmp_disconnect (handle, node, oplug, + raw1394_get_local_id (handle), iplug, channel, bandwidth); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + amdtp_receive (handle, f, 63); + } + } else { + amdtp_receive (handle, f, 63); + } + if (f != stdout) + fclose (f); + } + raw1394_destroy_handle (handle); + } else { + fprintf (stderr, "Failed to get libraw1394 handle\n"); + return -1; + } + + return 0; +} Index: /branches/libfreebob-1.4/freebob/tests/avc_extended_stream_format.h =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_extended_stream_format.h (revision 111) +++ /branches/libfreebob-1.4/freebob/tests/avc_extended_stream_format.h (revision 111) @@ -0,0 +1,381 @@ +/* avc_extended_stream_format.h + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#ifndef AVCExtendedStreamFormat_h +#define AVCExtendedStreamFormat_h + +#include "avc_generic.h" + +#include +#include +#include + +#define AVC1394_STREAM_FORMAT_SUPPORT 0x2F +#define AVC1394_STREAM_FORMAT_SUBFUNCTION_INPUT 0x00 +#define AVC1394_STREAM_FORMAT_SUBFUNCTION_OUTPUT 0x01 + +// BridgeCo extensions +#define AVC1394_STREAM_FORMAT_SUBFUNCTION_EXTENDED_STREAM_FORMAT 0xC0 +#define AVC1394_STREAM_FORMAT_SUBFUNCTION_EXTENDED_STREAM_FORMAT_LIST 0xC1 + + +#define AVC1394_STREAM_FORMAT_HIERARCHY_ROOT_DVCR 0x80 +#define AVC1394_STREAM_FORMAT_HIERARCHY_ROOT_AUDIOMUSIC 0x90 +#define AVC1394_STREAM_FORMAT_HIERARCHY_ROOT_INVALID 0xFF + +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_SD525_60 0x00 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_SDL525_60 0x04 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_HD1125_60 0x08 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_SD625_60 0x80 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_SDL625_50 0x84 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_HD1250_50 0x88 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_AM824 0x00 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_24_4_AUDIO_PACK 0x01 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_32_FLOATING_POINT_DATA 0x02 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_AM824_COMPOUND 0x40 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_DONT_CARE 0xFF + + +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC60968_3 0x00 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_3 0x01 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_4 0x02 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_5 0x03 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_6 0x04 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_7 0x05 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_MULTI_BIT_LINEAR_AUDIO_RAW 0x06 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_MULTI_BIT_LINEAR_AUDIO_DVD_AUDIO 0x07 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_ONE_BIT_AUDIO_PLAIN_RAW 0x08 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_ONE_BIT_AUDIO_PLAIN_SACD 0x09 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_ONE_BIT_AUDIO_ENCODED_RAW 0x0A +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_ONE_BIT_AUDIO_ENCODED_SACD 0x0B +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_HIGH_PRECISION_MULTIBIT_LINEAR_AUDIO 0x0C +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_MIDI_CONFORMANT 0x0D +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_SYNC_STREAM 0x40 +#define AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_DONT_CARE 0xFF + +#define AVC1394_STREAM_FORMAT_AM824_IEC60968_3 0x00 +#define AVC1394_STREAM_FORMAT_AM824_IEC61937_3 0x01 +#define AVC1394_STREAM_FORMAT_AM824_IEC61937_4 0x02 +#define AVC1394_STREAM_FORMAT_AM824_IEC61937_5 0x03 +#define AVC1394_STREAM_FORMAT_AM824_IEC61937_6 0x04 +#define AVC1394_STREAM_FORMAT_AM824_IEC61937_7 0x05 +#define AVC1394_STREAM_FORMAT_AM824_MULTI_BIT_LINEAR_AUDIO_RAW 0x06 +#define AVC1394_STREAM_FORMAT_AM824_MULTI_BIT_LINEAR_AUDIO_DVD_AUDIO 0x07 +#define AVC1394_STREAM_FORMAT_AM824_HIGH_PRECISION_MULTIBIT_LINEAR_AUDIO 0x0C +#define AVC1394_STREAM_FORMAT_AM824_MIDI_CONFORMANT 0x0D +#define AVC1394_STREAM_FORMAT_AM824_DONT_CARE 0xFF + +/* +// As defined in 'AV/C Stream Format Information Specification 1.0 TA Document 2001002' +// Not used for extended stream format +#define AVC1394_STREAM_FORMAT_SUPPORT_STATUS_SUPPORTED_AND_CONFIGURED 0x00 +#define AVC1394_STREAM_FORMAT_SUPPORT_STATUS_SUPPORTED_AND_HAS_NOT_BEEN_CONFIGURED 0x01 +#define AVC1394_STREAM_FORMAT_SUPPORT_STATUS_SUPPORTED_AND_READY_TO_CONFIGURE 0x02 +#define AVC1394_STREAM_FORMAT_SUPPORT_STATUS_SUPPORTED_AND_NOT_CONFIGURED 0x03 +#define AVC1394_STREAM_FORMAT_SUPPORT_STATUS_NOT_SUPPORTED 0x04 +// 0x05 - 0xFE reserved +#define AVC1394_STREAM_FORMAT_SUPPORT_STATUS_NO_INFORMATION 0xFF +*/ + +#define AVC1394_EXTENDED_STREAM_FORMAT_INFO_STATUS_ACTIVE 0x00 +#define AVC1394_EXTENDED_STREAM_FORMAT_INFO_STATUS_INACTIVE 0x01 +#define AVC1394_EXTENDED_STREAM_FORMAT_INFO_STATUS_NO_STREAM_FORMAT 0x02 +#define AVC1394_EXTENDED_STREAM_FORMAT_INFO_STATUS_NOT_USED 0xff + +class IOSSerialize; +class IISDeserialize; + +enum ERateControl { + eRC_Supported = 0x00, + eRC_DontCare = 0x01, +}; + +//////////////////////////////////////////////////////////// + +class PlugAddressData : public IBusData { +}; + +//////////////////////////////////////////////////////////// + +class UnitPlugAddress : public PlugAddressData +{ +public: + enum EPlugType { + ePT_PCR = 0x00, + ePT_ExternalPlug = 0x01, + ePT_AsynchronousPlug = 0x02, + }; + + UnitPlugAddress( EPlugType plugType, plug_type_t plugId ); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + virtual UnitPlugAddress* clone() const; + + plug_id_t m_plugType; + plug_type_t m_plugId; + reserved_t m_reserved; +}; + +//////////////////////////////////////////////////////////// + +class SubunitPlugAddress : public PlugAddressData +{ +public: + SubunitPlugAddress( plug_id_t plugId ); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + virtual SubunitPlugAddress* clone() const; + + plug_id_t m_plugId; + reserved_t m_reserved0; + reserved_t m_reserved1; +}; + +//////////////////////////////////////////////////////////// + +class FunctionBlockPlugAddress : public PlugAddressData +{ +public: + FunctionBlockPlugAddress( function_block_type_t functionBlockType, + function_block_id_t functionBlockId, + plug_id_t plugId ); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + virtual FunctionBlockPlugAddress* clone() const; + + function_block_type_t m_functionBlockType; + function_block_id_t m_functionBlockId; + plug_id_t m_plugId; +}; + +//////////////////////////////////////////////////////////// + +class PlugAddress : public IBusData { +public: + enum EPlugDirection { + ePD_Input = 0x00, + ePD_Output = 0x01, + }; + + enum EPlugAddressMode { + ePAM_Unit = 0x00, + ePAM_Subunit = 0x01, + ePAM_FunctionBlock = 0x02, + }; + + PlugAddress( EPlugDirection plugDirection, + EPlugAddressMode plugAddressMode, + UnitPlugAddress& unitPlugAddress ); + PlugAddress( EPlugDirection plugDirection, + EPlugAddressMode plugAddressMode, + SubunitPlugAddress& subUnitPlugAddress ); + PlugAddress( EPlugDirection plugDirection, + EPlugAddressMode plugAddressMode, + FunctionBlockPlugAddress& functionBlockPlugAddress ); + PlugAddress( const PlugAddress& pa ); + + virtual ~PlugAddress(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + + virtual PlugAddress* clone() const; + + plug_direction_t m_plugDirection; + plug_address_mode_t m_addressMode; + PlugAddressData* m_plugAddressData; +}; + + +//////////////////////////////////////////////////////////// + +class StreamFormatInfo: public IBusData +{ +public: + StreamFormatInfo(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + + virtual StreamFormatInfo* clone() const; + + number_of_channels_t m_numberOfChannels; + stream_format_t m_streamFormat; +}; + +//////////////////////////////////////////////////////////// + +class FormatInformationStreams: public IBusData +{ +public: + FormatInformationStreams() {} + virtual ~FormatInformationStreams() {} +}; + +//////////////////////////////////////////////////////////// + +class FormatInformationStreamsSync: public FormatInformationStreams +{ +public: + FormatInformationStreamsSync(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + virtual FormatInformationStreamsSync* clone() const; + + reserved_t m_reserved0; + sampling_frequency_t m_samplingFrequency; + rate_control_t m_rateControl; + reserved_t m_reserved1; +}; + +//////////////////////////////////////////////////////////// + +class FormatInformationStreamsCompound: public FormatInformationStreams +{ +public: + FormatInformationStreamsCompound(); + virtual ~FormatInformationStreamsCompound(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + virtual FormatInformationStreamsCompound* clone() const; + + sampling_frequency_t m_samplingFrequency; + rate_control_t m_rateControl; + number_of_stream_format_infos_t m_numberOfStreamFormatInfos; + + typedef std::vector< StreamFormatInfo* > StreamFormatInfoVector; + StreamFormatInfoVector m_streamFormatInfos; +}; + + +//////////////////////////////////////////////////////////// + +class FormatInformation: public IBusData +{ +public: + enum EFormatHierarchyRoot { + eFHR_DVCR = AVC1394_STREAM_FORMAT_HIERARCHY_ROOT_DVCR, + eFHR_AudioMusic = AVC1394_STREAM_FORMAT_HIERARCHY_ROOT_AUDIOMUSIC, + eFHR_Invalid = AVC1394_STREAM_FORMAT_HIERARCHY_ROOT_INVALID, + }; + + enum EFomatHierarchyLevel1 { + eFHL1_DVCR_SD525_60 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_SD525_60, + eFHL1_DVCR_SDL525_60 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_SDL525_60, + eFHL1_DVCR_HD1125_60 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_HD1125_60, + eFHL1_DVCR_SD625_60 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_SD625_60, + eFHL1_DVCR_SDL625_50 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_SDL625_50, + eFHL1_DVCR_HD1250_50 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_DVCR_HD1250_50, + eFHL1_AUDIOMUSIC_AM824 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_AM824, + eFHL1_AUDIOMUSIC_24_4_AUDIO_PACK = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_24_4_AUDIO_PACK, + eFHL1_AUDIOMUSIC_32_FLOATING = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_32_FLOATING_POINT_DATA, + eFHL1_AUDIOMUSIC_AM824_COMPOUND = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_AM824_COMPOUND, + eFHL1_AUDIOMUSIC_DONT_CARE = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_1_AUDIOMUSIC_DONT_CARE, + }; + + enum EFormatHierarchyLevel2 { + eFHL2_AM824_IEC60968_3 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC60968_3, + eFHL2_AM824_IEC61937_3 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_3, + eFHL2_AM824_IEC61937_4 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_4, + eFHL2_AM824_IEC61937_5 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_5, + eFHL2_AM824_IEC61937_6 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_6, + eFHL2_AM824_IEC61937_7 = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_IEC61937_7, + eFHL2_AM824_MULTI_BIT_LINEAR_AUDIO_RAW = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_MULTI_BIT_LINEAR_AUDIO_RAW, + eFHL2_AM824_MULTI_BIT_LINEAR_AUDIO_DVD_AUDIO = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_MULTI_BIT_LINEAR_AUDIO_DVD_AUDIO, + eFHL2_AM824_ONE_BIT_AUDIO_PLAIN_RAW = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_ONE_BIT_AUDIO_PLAIN_RAW, + eFHL2_AM824_ONE_BIT_AUDIO_PLAIN_SACD = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_ONE_BIT_AUDIO_PLAIN_SACD, + eFHL2_AM824_ONE_BIT_AUDIO_ENCODED_RAW = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_ONE_BIT_AUDIO_ENCODED_RAW, + eFHL2_AM824_ONE_BIT_AUDIO_ENCODED_SACD = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_ONE_BIT_AUDIO_ENCODED_SACD, + eFHL2_AM824_HIGH_PRECISION_MULTIBIT_LINEAR_AUDIO = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_HIGH_PRECISION_MULTIBIT_LINEAR_AUDIO, + eFHL2_AM824_MIDI_CONFORMANT = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_MIDI_CONFORMANT, + eFHL2_AM824_SYNC_STREAM = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_SYNC_STREAM, + eFHL2_AM824_DONT_CARE = AVC1394_STREAM_FORMAT_HIERARCHY_LEVEL_2_AM824_DONT_CARE, + }; + + typedef byte_t format_hierarchy_root_t; + typedef byte_t format_hierarchy_level1_t; + typedef byte_t format_hierarchy_level2_t; + + FormatInformation(); + virtual ~FormatInformation(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + + virtual FormatInformation* clone() const; + + format_hierarchy_root_t m_root; + format_hierarchy_level1_t m_level1; + format_hierarchy_level2_t m_level2; + FormatInformationStreams* m_streams; +}; + +/////////////////////////////////////////////////////////// + +class ExtendedStreamFormatCmd: public AVCCommand +{ +public: + enum ESubFunction { + eSF_Input = AVC1394_STREAM_FORMAT_SUBFUNCTION_INPUT, + eSF_Output = AVC1394_STREAM_FORMAT_SUBFUNCTION_OUTPUT, + eSF_ExtendedStreamFormatInformationCommand = AVC1394_STREAM_FORMAT_SUBFUNCTION_EXTENDED_STREAM_FORMAT, + eSF_ExtendedStreamFormatInformationCommandList = AVC1394_STREAM_FORMAT_SUBFUNCTION_EXTENDED_STREAM_FORMAT_LIST, + }; + + enum EStatus { + eS_Active = AVC1394_EXTENDED_STREAM_FORMAT_INFO_STATUS_ACTIVE, + eS_Inactive = AVC1394_EXTENDED_STREAM_FORMAT_INFO_STATUS_INACTIVE, + eS_NoStreamFormat = AVC1394_EXTENDED_STREAM_FORMAT_INFO_STATUS_NO_STREAM_FORMAT, + eS_NotUsed = AVC1394_EXTENDED_STREAM_FORMAT_INFO_STATUS_NOT_USED, + }; + typedef byte_t status_t; + typedef byte_t index_in_stream_format_t; + + ExtendedStreamFormatCmd( ESubFunction eSubFunction = eSF_ExtendedStreamFormatInformationCommand ); + virtual ~ExtendedStreamFormatCmd(); + + bool setPlugAddress( const PlugAddress& plugAddress ); + bool setIndexInStreamFormat( const int index ); + bool setSubFunction( ESubFunction subFunction ); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + + virtual bool fire( raw1394handle_t handle, + unsigned int node_id ); + + status_t getStatus(); + FormatInformation* getFormatInformation(); + index_in_stream_format_t getIndex(); + +protected: + subfunction_t m_subFunction; + PlugAddress* m_plugAddress; + status_t m_status; + index_in_stream_format_t m_indexInStreamFormat; + FormatInformation* m_formatInformation; +}; + +#endif // AVCExtendedStreamFormat_h Index: /branches/libfreebob-1.4/freebob/tests/convert.h =================================================================== --- /branches/libfreebob-1.4/freebob/tests/convert.h (revision 115) +++ /branches/libfreebob-1.4/freebob/tests/convert.h (revision 115) @@ -0,0 +1,44 @@ +/* convert.h + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#ifndef Convert_h +#define Convert_h + +#include +#include +#include +#include + +class BadConversion : public std::runtime_error { + public: + BadConversion(const std::string& s) + : std::runtime_error(s) + { } +}; + +inline std::string stringify(int x) +{ + std::ostringstream o; + if (!(o << x)) + throw BadConversion("stringify(int)"); + return o.str(); +} + +#endif // Convert_h Index: /branches/libfreebob-1.4/freebob/tests/avc_signal_source.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_signal_source.cpp (revision 119) +++ /branches/libfreebob-1.4/freebob/tests/avc_signal_source.cpp (revision 119) @@ -0,0 +1,371 @@ +/* avc_signal_source.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "avc_signal_source.h" +#include "serialize.h" + +#include +#include + +using namespace std; + +#define AVC1394_CMD_SIGNAL_SOURCE 0x1A + +SignalUnitAddress::SignalUnitAddress() + : m_plugId( ePI_Invalid ) +{ +} + +bool +SignalUnitAddress::serialize( IOSSerialize& se ) +{ + byte_t reserved = 0xff; + se.write( reserved, "SignalUnitAddress" ); + se.write( m_plugId, "SignalUnitAddress plugId" ); + return true; +} + +bool +SignalUnitAddress::deserialize( IISDeserialize& de ) +{ + byte_t operand; + de.read( &operand ); + de.read( &m_plugId ); + return true; +} + +SignalUnitAddress* +SignalUnitAddress::clone() const +{ + return new SignalUnitAddress( *this ); +} + +//////////////////////////////////////// + +SignalSubunitAddress::SignalSubunitAddress() + : m_subunitType( AVC1394_SUBUNIT_RESERVED ) + , m_subunitId( AVC1394_SUBUNIT_ID_RESERVED ) + , m_plugId( ePI_Invalid ) +{ +} + +bool +SignalSubunitAddress::serialize( IOSSerialize& se ) +{ + byte_t operand = ( m_subunitType << 3 ) | ( m_subunitId & 0x7 ); + se.write( operand, "SignalSubunitAddress subunitType & subunitId" ); + se.write( m_plugId, "SignalSubunitAddress plugId" ); + return true; +} + +bool +SignalSubunitAddress::deserialize( IISDeserialize& de ) +{ + byte_t operand; + de.read( &operand ); + m_subunitType = operand >> 3; + m_subunitId = operand & 0x7; + de.read( &m_plugId ); + return true; +} + +SignalSubunitAddress* +SignalSubunitAddress::clone() const +{ + return new SignalSubunitAddress( *this ); +} + +//////////////////////////////////////// + + +SignalSourceCmd::SignalSourceCmd() + : AVCCommand( AVC1394_CMD_SIGNAL_SOURCE ) + , m_resultStatus( 0xff ) + , m_outputStatus( 0xff ) + , m_conv( 0xff ) + , m_signalStatus( 0xff ) + , m_signalSource( 0 ) + , m_signalDestination( 0 ) +{ +} + +SignalSourceCmd::~SignalSourceCmd() +{ + delete m_signalSource; + m_signalSource = 0; + delete m_signalDestination; + m_signalDestination = 0; +} + +bool +SignalSourceCmd::serialize( IOSSerialize& se ) +{ + AVCCommand::serialize( se ); + + byte_t operand; + switch ( getCommandType() ) { + case eCT_Status: + operand = ( m_outputStatus << 5 ) + | ( ( m_conv & 0x1 ) << 4 ) + | ( m_signalStatus & 0xf ); + se.write( operand, "SignalSourceCmd outputStatus & conv & signalStatus" ); + break; + case eCT_Control: + case eCT_SpecificInquiry: + operand = m_resultStatus & 0xf; + se.write( operand, "SignalSourceCmd resultStatus" ); + break; + default: + cerr << "Can't handle command type " << getCommandType() << endl; + return false; + } + + switch( getSubunitType() ) { + case eST_Unit: + case eST_Audio: + case eST_Music: + { + if ( m_signalSource ) { + m_signalSource->serialize( se ); + } else { + byte_t reserved = 0xff; + se.write( reserved, "SignalSourceCmd" ); + se.write( reserved, "SignalSourceCmd" ); + } + + if ( m_signalDestination ) { + m_signalDestination->serialize( se ); + } else { + byte_t reserved = 0xff; + se.write( reserved, "SignalSourceCmd" ); + se.write( reserved, "SignalSourceCmd" ); + } + } + break; + default: + cerr << "Can't handle subunit type " << getSubunitType() << endl; + return false; + } + + return true; +} + +bool +SignalSourceCmd::deserialize( IISDeserialize& de ) +{ + delete m_signalSource; + m_signalSource = 0; + delete m_signalDestination; + m_signalDestination = 0; + + AVCCommand::deserialize( de ); + + byte_t operand; + switch ( getCommandType() ) { + case eCT_Status: + de.read( &operand ); + m_outputStatus = operand >> 5; + m_conv = ( operand & 0x10 ) >> 4; + m_signalStatus = operand & 0xf; + break; + case eCT_Control: + case eCT_SpecificInquiry: + de.read( &operand ); + m_resultStatus = operand & 0xf; + break; + default: + cerr << "Can't handle command type " << getCommandType() << endl; + return false; + } + + switch( getSubunitType() ) { + case eST_Unit: + case eST_Audio: + case eST_Music: + { + byte_t operand; + de.peek( &operand ); + if ( operand == 0xff ) { + m_signalSource = new SignalUnitAddress; + } else { + m_signalSource = new SignalSubunitAddress; + } + + m_signalSource->deserialize( de ); + + de.peek( &operand ); + if ( operand == 0xff ) { + m_signalDestination = new SignalUnitAddress; + } else { + m_signalDestination = new SignalSubunitAddress; + } + m_signalDestination->deserialize( de ); + } + break; + default: + cerr << "Can't handle subunit type " << getSubunitType() << endl; + return false; + } + + return true; +} + +bool +SignalSourceCmd::fire( raw1394handle_t handle, + unsigned int node_id ) +{ + bool result = false; + + #define STREAM_FORMAT_REQUEST_SIZE 5 // XXX random length + union UPacket { + quadlet_t quadlet[STREAM_FORMAT_REQUEST_SIZE]; + unsigned char byte[STREAM_FORMAT_REQUEST_SIZE*4]; + }; + typedef union UPacket packet_t; + + packet_t req; + packet_t* resp; + + // initialize complete packet + memset( &req, 0xff, sizeof( req ) ); + + BufferSerialize se( req.byte, sizeof( req ) ); + if ( !serialize( se ) ) { + printf( "SignalSourceCmd::fire: Could not serialize\n" ); + return false; + } + + // reorder the bytes to the correct layout + for (int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i) { + req.quadlet[i] = ntohl( req.quadlet[i] ); + } + + if ( isVerbose() ) { + // debug output + puts("request:"); + for (int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i) { + printf(" %2d: 0x%08x\n", i, req.quadlet[i]); + } + } + + resp = reinterpret_cast ( avc1394_transaction_block( handle, node_id, req.quadlet, STREAM_FORMAT_REQUEST_SIZE, 1 ) ); + if ( resp ) { + if ( isVerbose() ) { + // debug output + puts("response:"); + for ( int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i ) { + printf( " %2d: 0x%08x\n", i, resp->quadlet[i] ); + } + } + + // reorder the bytes to the correct layout + for ( int i = 0; i < STREAM_FORMAT_REQUEST_SIZE; ++i ) { + resp->quadlet[i] = htonl( resp->quadlet[i] ); + } + + if ( isVerbose() ) { + // a more detailed debug output + printf( "\n" ); + printf( " idx type value\n" ); + printf( "-------------------------------------\n" ); + printf( " %02d ctype: 0x%02x\n", 0, resp->byte[0] ); + printf( " %02d subunit_type + subunit_id: 0x%02x\n", 1, resp->byte[1] ); + printf( " %02d opcode: 0x%02x\n", 2, resp->byte[2] ); + + for ( int i = 3; i < STREAM_FORMAT_REQUEST_SIZE * 4; ++i ) { + printf( " %02d operand %2d: 0x%02x\n", i, i-3, resp->byte[i] ); + } + } + + // parse output + parseResponse( resp->byte[0] ); + switch ( getResponse() ) + { + case eR_Implemented: + case eR_NotImplemented: + case eR_Accepted: + case eR_Rejected: + { + BufferDeserialize de( resp->byte, sizeof( req ) ); + deserialize( de ); + result = true; + } + break; + default: + printf( "unexpected response received (0x%x)\n", getResponse() ); + } + } else { + printf( "no response\n" ); + } + + return result; +} + +bool +SignalSourceCmd::setSignalSource( SignalUnitAddress& signalAddress ) +{ + if ( m_signalSource ) { + delete m_signalSource; + } + m_signalSource = signalAddress.clone(); + return true; +} + +bool +SignalSourceCmd::setSignalSource( SignalSubunitAddress& signalAddress ) +{ + if ( m_signalSource ) { + delete m_signalSource; + } + m_signalSource = signalAddress.clone(); + return true; +} + +bool +SignalSourceCmd::setSignalDestination( SignalUnitAddress& signalAddress ) +{ + if ( m_signalDestination ) { + delete m_signalDestination; + } + m_signalDestination = signalAddress.clone(); + return true; +} + +bool +SignalSourceCmd::setSignalDestination( SignalSubunitAddress& signalAddress ) +{ + if ( m_signalDestination ) { + delete m_signalDestination; + } + m_signalDestination = signalAddress.clone(); + return true; +} + +SignalAddress* +SignalSourceCmd::getSignalSource() +{ + return m_signalSource; +} + +SignalAddress* +SignalSourceCmd::getSignalDestination() +{ + return m_signalDestination; +} Index: /branches/libfreebob-1.4/freebob/tests/serialize.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/serialize.cpp (revision 119) +++ /branches/libfreebob-1.4/freebob/tests/serialize.cpp (revision 119) @@ -0,0 +1,122 @@ +/* serialize.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "serialize.h" + +#include +#include + +using namespace std; + +bool +CoutSerializer::write( byte_t d, const char* name ) +{ + cout << name << ": 0x" << setfill( '0' ) << hex << static_cast( d ) << endl; + return true; +} + +bool +CoutSerializer::write( quadlet_t d, const char* name ) +{ + cout << name << ": 0x" << setfill( '0' ) << setw( 8 ) << hex << d << endl; + return true; +} + +////////////////////////////////////////////////// + +bool +BufferSerialize::write( byte_t value, const char* name ) +{ + bool result = false; + if ( isCurPosValid() ) { + *m_curPos = value; + m_curPos += sizeof( byte_t ); + result = true; + } + return result; +} + +bool +BufferSerialize::write( quadlet_t value, const char* name ) +{ + bool result = false; + if ( isCurPosValid() ) { + * ( quadlet_t* )m_curPos = value; + m_curPos += sizeof( quadlet_t ); + result = true; + } + return result; +} + +bool +BufferSerialize::isCurPosValid() const +{ + if ( static_cast( ( m_curPos - m_buffer ) ) >= m_length ) { + return false; + } + return true; +} + +////////////////////////////////////////////////// + +bool +BufferDeserialize::read( byte_t* value ) +{ + bool result = false; + if ( isCurPosValid() ) { + *value = *m_curPos; + m_curPos += sizeof( byte_t ); + result = true; + } + return result; +} + +bool +BufferDeserialize::read( quadlet_t* value ) +{ + bool result = false; + if ( isCurPosValid() ) { + *value = *m_curPos; + m_curPos += sizeof( quadlet_t ); + result = true;; + } + return result; +} + +bool +BufferDeserialize::peek( byte_t* value ) +{ + bool result = false; + if ( isCurPosValid() ) { + *value = *m_curPos; + result = true; + } + return result; +} + +bool +BufferDeserialize::isCurPosValid() const +{ + if ( static_cast( ( m_curPos - m_buffer ) ) >= m_length ) { + return false; + } + return true; +} + Index: /branches/libfreebob-1.4/freebob/tests/csr1212_read.c =================================================================== --- /branches/libfreebob-1.4/freebob/tests/csr1212_read.c (revision 78) +++ /branches/libfreebob-1.4/freebob/tests/csr1212_read.c (revision 78) @@ -0,0 +1,243 @@ +/* csr1212_read.c + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +/* The process_unit_directory and process_root_directory function are + * based on code from linux-2.6.11/drivers/ieee1394/nodemgr.c. + */ + +#include +#include +#include +#include +#include "../src/csr1212.h" + +struct freebob_csr_info { + raw1394handle_t handle; + int node_id; +}; + +static int +freebob_bus_read(struct csr1212_csr* csr, u_int64_t addr, u_int16_t length, + void* buffer, void* private) +{ + struct freebob_csr_info* csr_info = (struct freebob_csr_info*) private; + /* + printf("freebob_bus_read: node id = %d, addr = 0x%08x%08x, length = %d\n", + csr_info->node_id, + (unsigned int)(addr >> 32), (unsigned int)(addr &0xffffffff), + length); + */ + + unsigned int retval; + retval=raw1394_read(csr_info->handle, csr_info->node_id, addr, + length, buffer); + if (retval) { + perror("read failed"); + } else { + #if 0 + fprintf(stdout,"read succeeded. Data follows (hex):\n"); + int i; + for (i=0; i < length; i++) { + fprintf(stdout,(i+1) % 4?"%.2X ":"%.2X\n", ((unsigned char*)buffer)[i]); + } + if (i % 4) fprintf(stdout,"\n"); + #endif + } + + return retval; +} + +static int +freebob_get_max_rom(u_int32_t* bus_info_data, void* private) +{ + return (CSR1212_BE32_TO_CPU(bus_info_data[2]) >> 8) & 0x3; +} + +static struct csr1212_bus_ops freebob_csr_ops = { + .bus_read = freebob_bus_read, + .get_max_rom = freebob_get_max_rom +}; + +static void +process_unit_directory(struct csr1212_csr* csr, + struct csr1212_keyval *ud_kv, + unsigned int *id) +{ + struct csr1212_dentry *dentry; + struct csr1212_keyval *kv; + unsigned int last_key_id = 0; + + printf("process unit directory:\n"); + csr1212_for_each_dir_entry(csr, kv, ud_kv, dentry) { + switch (kv->key.id) { + case CSR1212_KV_ID_VENDOR: + if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { + printf("\tvendor_id = 0x%08x\n", + kv->value.immediate); + } + break; + + case CSR1212_KV_ID_MODEL: + printf("\tmodel_id = 0x%08x\n", + kv->value.immediate); + break; + + case CSR1212_KV_ID_SPECIFIER_ID: + printf("\tspecifier_id = 0x%08x\n", + kv->value.immediate); + break; + + case CSR1212_KV_ID_VERSION: + printf("\tversion = 0x%08x\n", + kv->value.immediate); + break; + + case CSR1212_KV_ID_DESCRIPTOR: + if (kv->key.type == CSR1212_KV_TYPE_LEAF && + CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 && + CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) + { + switch (last_key_id) { + case CSR1212_KV_ID_VENDOR: + csr1212_keep_keyval(kv); + break; + + case CSR1212_KV_ID_MODEL: + csr1212_keep_keyval(kv); + break; + + } + } /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */ + break; + + case CSR1212_KV_ID_DEPENDENT_INFO: + if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) { + /* This should really be done in SBP2 as this is + * doing SBP2 specific parsing. */ + process_unit_directory(csr, kv, id); + } + + break; + + default: + break; + } + last_key_id = kv->key.id; + } +} + +static void +process_root_directory(struct csr1212_csr* csr) +{ + unsigned int ud_id = 0; + struct csr1212_dentry *dentry; + struct csr1212_keyval *kv; + unsigned int last_key_id = 0; + + csr1212_for_each_dir_entry(csr, kv, csr->root_kv, dentry) { + switch (kv->key.id) { + case CSR1212_KV_ID_VENDOR: + printf("vendor id = 0x%08x\n", kv->value.immediate); + break; + + case CSR1212_KV_ID_NODE_CAPABILITIES: + printf("capabilities = 0x%08x\n", kv->value.immediate); + break; + + case CSR1212_KV_ID_UNIT: + process_unit_directory(csr, kv, &ud_id); + break; + + case CSR1212_KV_ID_DESCRIPTOR: + if (last_key_id == CSR1212_KV_ID_VENDOR) { + if (kv->key.type == CSR1212_KV_TYPE_LEAF && + CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 && + CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) { + csr1212_keep_keyval(kv); + } + } + break; + } + last_key_id = kv->key.id; + } +} + + +int +main(int argc, char* argv[]) +{ + if (argc != 2) { + printf("usage: %s NODE_ID\n", argv[0]); + return 0; + } + errno = 0; + char* tail; + int node_id = strtol(argv[1], &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return -1; + } + + raw1394handle_t handle; + handle = raw1394_new_handle (); + if (!handle) { + if (!errno) { + perror("lib1394raw not compatable\n"); + } else { + fprintf(stderr, "Could not get 1394 handle"); + fprintf(stderr, "Is ieee1394, driver, and raw1394 loaded?\n"); + } + return -1; + } + + if (raw1394_set_port(handle, 0) < 0) { + fprintf(stderr, "Could not set port"); + raw1394_destroy_handle (handle); + return -1; + } + + struct freebob_csr_info csr_info; + csr_info.handle = handle; + csr_info.node_id = 0xffc0 | node_id; + + struct csr1212_csr* csr; + csr = csr1212_create_csr(&freebob_csr_ops, + 5 * sizeof(quadlet_t), + &csr_info); + if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) { + fprintf(stderr, "couldn't parse config rom\n"); + if (csr) { + csr1212_destroy_csr(csr); + } + return -1; + } + + process_root_directory(csr); + + csr1212_destroy_csr(csr); + + return 0; +} Index: /branches/libfreebob-1.4/freebob/tests/Makefile.am =================================================================== --- /branches/libfreebob-1.4/freebob/tests/Makefile.am (revision 108) +++ /branches/libfreebob-1.4/freebob/tests/Makefile.am (revision 108) @@ -0,0 +1,22 @@ +noinst_PROGRAMS = byte_order detect_avc_unit stream_format sync_mode get-xml-description \ + test-freebob-midi test-freebob-audio test-freebob-iso test-freebob-synctransfer csr1212_read \ + test-freebob-bounce + + +byte_order_SOURCES = byte_order.c +detect_avc_unit_SOURCES = detect_avc_unit.c +stream_format_SOURCES = stream_format.cpp avc_extended_stream_format.cpp serialize.cpp avc_generic.cpp avc_definitions.cpp +sync_mode_SOURCES = sync_mode.cpp avc_extended_stream_format.cpp serialize.cpp avc_generic.cpp avc_plug_info.cpp avc_definitions.cpp avc_signal_source.cpp +test_freebob_midi_SOURCES = test-freebob-midi.c +test_freebob_audio_SOURCES = test-freebob-audio.c +test_freebob_iso_SOURCES = test-freebob-iso.c +test_freebob_bounce_SOURCES = test-freebob-bounce.c +test_freebob_synctransfer_SOURCES = test-freebob-synctransfer.c +csr1212_read_SOURCES = ../src/csr1212.c ../src/csr1212.h csr1212_read.c +get_xml_description_SOURCES = get-xml-description.c + +INCLUDES = $(LIBSIGC_CFLAGS) $(LIBRAW1394_CFLAGS) $(LIBIEC61883_CFLAGS) $(ALSA_CFLAGS) $(LIBLO_CFLAGS) +LDADD = $(LIBSIGC_LIBS) $(LIBRAW1394_LIBS) $(LIBIEC61883_LIBS) $(LIBAVC_LIBS) $(ALSA_LIBS) $(LIBLO_LIBS) -ljack +AM_CFLAGS = "-std=c99" + +MAINTAINERCLEANFILES = Makefile.in Index: /branches/libfreebob-1.4/freebob/tests/test-freebob-bounce.c =================================================================== --- /branches/libfreebob-1.4/freebob/tests/test-freebob-bounce.c (revision 97) +++ /branches/libfreebob-1.4/freebob/tests/test-freebob-bounce.c (revision 97) @@ -0,0 +1,613 @@ +/* + * FreeBob Test Program + * Bounces all input back to the sender + * Copyright (C) 2005 Pieter Palmers + * + * Timing code shamelessly copied from Mixxx source code + * (C) 2002 by Tue and Ken Haste Andersen + */ + +/* Based upon code from: + * libiec61883 - Linux IEEE 1394 streaming media library. + * Copyright (C) 2004 Kristian Hogsberg and Dan Dennedy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * ./test-freebob-bounce + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + + #define QUATAFIRE_DEFAULT_SAMPLE_RATE 48000 + #define QUATAFIRE_OUT_DIMENSION 11 + #define QUATAFIRE_IN_DIMENSION 7 + #define QUATAFIRE_INPUT_TARGET_CHANNEL 1 + #define QUATAFIRE_MIDI_OUT_STREAM_POSITION 10 + +//enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_DEFAULT; +enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_BUFFERFILL; +//enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_PACKET_PER_BUFFER; +//#define BUFFER 1000 +//#define IRQ 20 +//#define PACKET_MAX 8192 + +#if __BYTE_ORDER == __BIG_ENDIAN + +struct iso_packet_header { + unsigned int data_length : 16; + unsigned int tag : 2; + unsigned int channel : 6; + unsigned int tcode : 4; + unsigned int sy : 4; +}; + +struct iec61883_packet { + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + unsigned char data[0]; +}; + +typedef struct packet_info packet_info_t; +struct packet_info { + /* The first part of this structure is a copy of the CIP header + * This can be memcpy'd from the packet itself. + */ + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + /* the second part is some extra info */ + unsigned int nevents; + unsigned int length; +}; + +#elif __BYTE_ORDER == __LITTLE_ENDIAN + +struct iso_packet_header { + unsigned int data_length : 16; + unsigned int channel : 6; + unsigned int tag : 2; + unsigned int sy : 4; + unsigned int tcode : 4; +}; + +struct iec61883_packet { + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + unsigned char data[0]; +}; + +typedef struct packet_info packet_info_t; +struct packet_info { + /* The first part of this structure is a copy of the CIP header + * This can be memcpy'd from the packet itself. + */ + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + /* the second part is some extra info */ + unsigned int nevents; + unsigned int length; +}; + + +#else + +#error Unknown bitfield type + +#endif + +typedef struct connection_info connection_info_t; +struct connection_info { + int packets; + int events; + int total_packets; + int total_events; + + int dropped; + + unsigned long handler_time; + + int packet_info_table_size; + packet_info_t *packet_info_table; + + connection_info_t *master; + + jack_ringbuffer_t *buffer; + +}; + +inline unsigned long getCurrentUTime() { + struct timeval now; + gettimeofday(&now, NULL); + return now.tv_sec*1000000+now.tv_usec; +} + +static int g_done = 0; + +static void sighandler (int sig) +{ + g_done = 1; +} + +static enum raw1394_iso_disposition +iso_master_receive_handler(raw1394handle_t handle, unsigned char *data, + unsigned int length, unsigned char channel, + unsigned char tag, unsigned char sy, unsigned int cycle, + unsigned int dropped) +{ + enum raw1394_iso_disposition retval; + + static unsigned int counter = 0; + int writelen; + unsigned long timestamp_enter=getCurrentUTime(); + + + connection_info_t *info = (connection_info_t *)raw1394_get_userdata(handle); + + struct iec61883_packet *packet = (struct iec61883_packet *) data; + + if(!info) { + fprintf(stderr,"invalid connection info handle"); + return RAW1394_ISO_ERROR; + } + + info->dropped+=dropped; + + if(info->packets< (info->packet_info_table_size)) { + // copy the packet_info from the packet to the packet_info_table + memcpy((void *)(&info->packet_info_table[info->packets]),packet,8); // the CIP header is 8 bytes long + + info->packet_info_table[info->packets].nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs; + info->packet_info_table[info->packets].length=length; + + // add the data payload to the ringbuffer + // rb_add(packet->data); + writelen= jack_ringbuffer_write(info->buffer, (const char *)(data+8), length - 8 ); + if(writelen < length-8) { + fprintf(stderr,"ringbuffer overrun\n"); + } + + // keep track of the total amount of events received + info->events+=info->packet_info_table[info->packets].nevents; + + // one packet received + info->packets++; + + //printf("MASTER RCV: FDF code = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n", packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, length,((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped); + retval=RAW1394_ISO_OK; + + } else { + // this shouldn't occur, because exiting raw_loop_iterate() should have freed up some space. + printf("MASTER RCV: Buffer overrun!\n"); + retval=RAW1394_ISO_ERROR; + } + + /* Check if the packet table is full. if so instruct libraw to leave raw1394_loop_iterate() + */ + if(info->packets==info->packet_info_table_size) { + // we processed this packet, but it is the last one we can queue in the packet_info_table. + // make sure we leave raw1394_loop_iterate() + retval=RAW1394_ISO_DEFER; + } + + info->handler_time+=(getCurrentUTime()-timestamp_enter); + + return retval; +} + +static enum raw1394_iso_disposition +iso_slave_transmit_handler(raw1394handle_t handle, + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + int cycle, unsigned int dropped) +{ + enum raw1394_iso_disposition retval; + + static unsigned int counter = 0; + + int readlen; + unsigned long timestamp_enter=getCurrentUTime(); + + connection_info_t *info = (connection_info_t *)raw1394_get_userdata(handle); + connection_info_t *master_info; + packet_info_t *master_packet_info; + + struct iec61883_packet *packet = (struct iec61883_packet *) data; + + if(!info) { + fprintf(stderr,"invalid connection info handle"); + return RAW1394_ISO_ERROR; + } + + master_info=info->master; + if(!master_info) { + fprintf(stderr,"invalid master connection info handle"); + return RAW1394_ISO_ERROR; + } + + info->dropped+=dropped; + + if(info->packets< (master_info->packet_info_table_size)) { + master_packet_info=&master_info->packet_info_table[info->packets]; + + // copy the packet_info from the packet_info_table to the packet + memcpy(packet,(void *)(master_packet_info),8); // the CIP header is 8 bytes long + + *tag = 1; + *sy = 0; + *length=master_packet_info->length; + + // read the data payload from the ringbuffer + readlen=jack_ringbuffer_read(info->buffer, (const char *)(data+8), master_packet_info->length - 8 ); + if(readlen < master_packet_info->length - 8) { + fprintf(stderr,"ringbuffer underrun\n"); + } + + // one packet received + info->packets++; + + // keep track of the total amount of events received + info->events+=master_packet_info->nevents; + //printf("SLAVE XMT: FDF code = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n", packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,master_packet_info->nevents, dropped); + retval=RAW1394_ISO_OK; + + } else { + // this shouldn't occur, because exiting raw_loop_iterate() should have freed up some space. + printf("SLAVE XMT: Buffer overrun!\n"); + retval=RAW1394_ISO_ERROR; + } + + if(info->packets==(master_info->packet_info_table_size)) { + retval=RAW1394_ISO_DEFER; + } + + info->handler_time+=(getCurrentUTime()-timestamp_enter); + + return retval; +} + +int main (int argc, char *argv[]) +{ + raw1394handle_t master_receive_handle = raw1394_new_handle(); + raw1394handle_t slave_transmit_handle = raw1394_new_handle(); + raw1394handle_t plug_handle = raw1394_new_handle(); + + unsigned long timestamp_start; + unsigned long timestamp_wait_receive; + unsigned long timestamp_end_transmit; + + int irq=100; + int BUFFER=1000; + int PACKET_MAX=1024; + int TABLE_SIZE=8; + int PREBUFFER=0; + int port=0; + + int i; + + int master_receive_iso_channel; + int master_receive_bandwidth = -1; + int master_receive_iplug=-1; + int master_receive_oplug=0; + nodeid_t master_receive_node = 0xffc0; + + int slave_transmit_iso_channel; + int slave_transmit_bandwidth = -1; + int slave_transmit_iplug=0; + int slave_transmit_oplug=-1; + nodeid_t slave_transmit_node = 0xffc0; + + jack_ringbuffer_t *ringbuffer; + + signal (SIGINT, sighandler); + signal (SIGPIPE, sighandler); + + for (i = 1; i < argc; i++) { + + if (strncmp (argv[i], "-h", 2) == 0 || + strncmp (argv[i], "--h", 3) == 0) + { + fprintf (stderr, + "usage: %s", argv[0]); + raw1394_destroy_handle (master_receive_handle); + raw1394_destroy_handle (slave_transmit_handle); + raw1394_destroy_handle (plug_handle); + return 1; + } else if (strncmp (argv[i], "-b", 2) == 0) { + BUFFER = atoi (argv[++i]); + } else if (strncmp (argv[i], "-l", 2) == 0) { + PREBUFFER = atoi (argv[++i]); + } else if (strncmp (argv[i], "-p", 2) == 0) { + PACKET_MAX = atoi (argv[++i]); + } else if (strncmp (argv[i], "-t", 2) == 0) { + TABLE_SIZE = atoi (argv[++i]); + } else if (strncmp (argv[i], "-i", 2) == 0) { + irq = atoi (argv[++i]); + } else if (strncmp (argv[i], "-o", 2) == 0) { + port = atoi (argv[++i]); + } + } + + if ((raw1394_set_port(master_receive_handle, port) < 0) || (raw1394_set_port(slave_transmit_handle, port) < 0) || (raw1394_set_port(plug_handle, port) < 0)) { + perror("couldn't set port"); + raw1394_destroy_handle (master_receive_handle); + raw1394_destroy_handle (slave_transmit_handle); + raw1394_destroy_handle (plug_handle); + return 1; + } + + fprintf (stderr, "Init Plugs...\n"); + + iec61883_plug_impr_init (plug_handle, IEC61883_DATARATE_400); + iec61883_plug_ompr_init (plug_handle, IEC61883_DATARATE_400, 63); + + iec61883_plug_ipcr_add (plug_handle, 1); + iec61883_plug_ipcr_add (plug_handle, 1); + iec61883_plug_opcr_add (plug_handle, 1,IEC61883_OVERHEAD_512,2048); + iec61883_plug_opcr_add (plug_handle, 1,IEC61883_OVERHEAD_512,2048); + + int g_incoming=0; + int g_outgoing=0; + + fprintf (stderr, "Wait for plug connections...\n"); + while (!g_done && (!g_incoming || !g_outgoing) ) { + fprintf (stderr, "something happened at the plugs: %d ...\n", raw1394_loop_iterate(plug_handle)); + } + +//#define TABLE_SIZE 4 +//#define PREBUFFER 0 +#define RINGBUFFER_SIZE_EVENTS TABLE_SIZE * 11 * 8 // nb packets * frames/event * events/packet + + connection_info_t master_receive_connection_info; + memset(&master_receive_connection_info,'\0',sizeof(connection_info_t)); + master_receive_connection_info.packet_info_table_size=TABLE_SIZE; + + master_receive_connection_info.packet_info_table=calloc(master_receive_connection_info.packet_info_table_size,sizeof(packet_info_t)); + + if (!master_receive_connection_info.packet_info_table) { + fprintf (stderr, "Could not allocate memory for master packet info table\n"); + return -ENOMEM; + } + + connection_info_t slave_transmit_connection_info; + memset(&slave_transmit_connection_info,'\0',sizeof(connection_info_t)); + slave_transmit_connection_info.master=&master_receive_connection_info; + + if (master_receive_handle) { + + ringbuffer = jack_ringbuffer_create (RINGBUFFER_SIZE_EVENTS * sizeof (quadlet_t)); + master_receive_connection_info.buffer=ringbuffer; + slave_transmit_connection_info.buffer=ringbuffer; + + raw1394_set_userdata(master_receive_handle,&master_receive_connection_info); + + fprintf (stderr, "** Master receive...\n"); + fprintf (stderr, "Create CMP connection...\n"); + //channel = iec61883_cmp_connect (handle, raw1394_get_local_id (handle), &oplug, node, &iplug, &bandwidth); + //master_receive_iso_channel = iec61883_cmp_connect (master_receive_handle, master_receive_node , &master_receive_oplug, raw1394_get_local_id (master_receive_handle), &master_receive_iplug, &master_receive_bandwidth); + + if (master_receive_iso_channel > -1) { + fprintf (stderr, "Init ISO master receive handler on channel %d...\n",master_receive_iso_channel); + fprintf (stderr, " other mode (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",BUFFER,PACKET_MAX, irq); + raw1394_iso_recv_init(master_receive_handle, iso_master_receive_handler, BUFFER, PACKET_MAX, master_receive_iso_channel, mode, irq); + + fprintf (stderr, "Start ISO master receive...\n"); + raw1394_iso_recv_start(master_receive_handle, -1, -1, 0); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + } + + if (slave_transmit_handle) { + fprintf (stderr, "** Slave transmit...\n"); + raw1394_set_userdata(slave_transmit_handle,&slave_transmit_connection_info); + fprintf (stderr, "Create CMP connection...\n"); + + //slave_transmit_iso_channel = iec61883_cmp_connect (slave_transmit_handle, raw1394_get_local_id (slave_transmit_handle), &slave_transmit_oplug, slave_transmit_node, &slave_transmit_iplug, &slave_transmit_bandwidth); + + if (slave_transmit_iso_channel > -1) { + fprintf (stderr, "Init ISO slave transmit handler on channel %d...\n",slave_transmit_iso_channel); + fprintf (stderr, " other mode (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",BUFFER,PACKET_MAX, irq); + raw1394_iso_xmit_init(slave_transmit_handle, iso_slave_transmit_handler, BUFFER, PACKET_MAX, slave_transmit_iso_channel, RAW1394_ISO_SPEED_400, irq); + + fprintf (stderr, "Start ISO slave transmit... PREBUFFER=%d\n",PREBUFFER); + raw1394_iso_xmit_start(slave_transmit_handle, -1, PREBUFFER); + } else { + fprintf (stderr, "Connect failed, reverting to broadcast channel 63.\n"); + } + } else { + fprintf (stderr, "Failed to get transmit libraw1394 handle\n %d: %s\nContinuing without transmitting\n",errno,strerror(errno)); + } + + fprintf (stderr, "Running raw1394_loop_iterate()...\n"); + + int packetcount=0; + +// polled receive loop + while (!g_done) { + int i=0,j=0; + // wait for enough packets + timestamp_start=getCurrentUTime(); + while ((raw1394_loop_iterate(master_receive_handle) == 0) && (master_receive_connection_info.packets < TABLE_SIZE)) { + + i++; + } + timestamp_wait_receive=getCurrentUTime(); + + /* + printf("LOOP: i = %4d. packets = %4d, events = %4d, total_packets = %6d, total_events = %6d, dropped = %6d\n", + i, + master_receive_connection_info.packets, + master_receive_connection_info.events, + master_receive_connection_info.total_packets, + master_receive_connection_info.total_events, + master_receive_connection_info.dropped); + */ + //printf(" rb_readspace = %6d, rb_writespace = %6d\n",jack_ringbuffer_read_space(ringbuffer),jack_ringbuffer_write_space(ringbuffer)); + + if(slave_transmit_handle) { + j=0; + while ((raw1394_loop_iterate(slave_transmit_handle) == 0) && (slave_transmit_connection_info.packets < master_receive_connection_info.packets )) { + + j++; + } + + /* + printf(" j = %4d. packets = %4d, events = %4d, total_packets = %6d, total_events = %6d, dropped = %6d\n", + j, + slave_transmit_connection_info.packets, + slave_transmit_connection_info.events, + slave_transmit_connection_info.total_packets, + slave_transmit_connection_info.total_events, + slave_transmit_connection_info.dropped); + */ + // consume + slave_transmit_connection_info.total_packets+=slave_transmit_connection_info.packets; + slave_transmit_connection_info.total_events+=slave_transmit_connection_info.events; + slave_transmit_connection_info.packets=0; + slave_transmit_connection_info.events=0; + + } + timestamp_end_transmit=getCurrentUTime(); + + // consume + master_receive_connection_info.total_packets+=master_receive_connection_info.packets; + master_receive_connection_info.total_events+=master_receive_connection_info.events; + master_receive_connection_info.packets=0; + master_receive_connection_info.events=0; + + fprintf(stderr,"%06.03f %06.03f %06.03f %06.03f\r", + (float)(master_receive_connection_info.handler_time/master_receive_connection_info.total_packets/1000.0), + (float)(slave_transmit_connection_info.handler_time/slave_transmit_connection_info.total_packets/1000.0), + (float)(timestamp_wait_receive/1000.0-timestamp_start/1000.0), + (float)(timestamp_end_transmit/1000.0-timestamp_wait_receive/1000.0) + ); + //printf(" rb_readspace = %6d, rb_writespace = %6d\n",jack_ringbuffer_read_space(ringbuffer),jack_ringbuffer_write_space(ringbuffer)); + } + + + fprintf (stderr, "Shutdown...\n"); + raw1394_iso_stop(master_receive_handle); + raw1394_iso_shutdown(master_receive_handle); + + if (slave_transmit_handle) { + raw1394_iso_stop(slave_transmit_handle); + raw1394_iso_shutdown(slave_transmit_handle); + } + + fprintf (stderr, "Closing CMP connection...\n"); + + + + //iec61883_cmp_disconnect (master_receive_handle, master_receive_node, master_receive_oplug, raw1394_get_local_id (master_receive_handle), master_receive_iplug, master_receive_iso_channel, master_receive_bandwidth); + + iec61883_plug_impr_close (plug_handle); + iec61883_plug_ompr_close (plug_handle); + + raw1394_destroy_handle(master_receive_handle); + + + if (slave_transmit_handle) { + raw1394_destroy_handle(slave_transmit_handle); + } + if (plug_handle) { + raw1394_destroy_handle (plug_handle); + } + + jack_ringbuffer_free(ringbuffer); + + } else { + fprintf (stderr, "Failed to get libraw1394 handle\n %d: %s\n",errno,strerror(errno)); + return -1; + } + + return 0; +} Index: /branches/libfreebob-1.4/freebob/tests/test_debug_module.cpp =================================================================== --- /branches/libfreebob-1.4/freebob/tests/test_debug_module.cpp (revision 43) +++ /branches/libfreebob-1.4/freebob/tests/test_debug_module.cpp (revision 43) @@ -0,0 +1,79 @@ +/* test_debug_module.cpp + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#include "../src/debugmodule.h" + +class TestDebugModule { +public: + + TestDebugModule() { + setDebugLevel( DEBUG_LEVEL_ALL ); + } + + ~TestDebugModule() {} + + void run() { + + // Simpel output + debugPrint( DEBUG_LEVEL_INFO, "DEBUG_LEVEL_INFO\n" ); + debugPrint( DEBUG_LEVEL_DEVICE, "DEBUG_LEVEL_DEVICE\n" ); + debugPrint( DEBUG_LEVEL_SUBUNIT, "DEBUG_LEVEL_SUBUNIT\n" ); + debugPrint( DEBUG_LEVEL_DESCRIPTOR, "DEBUG_LEVEL_DESCRIPTOR\n" ); + debugPrint( DEBUG_LEVEL_INFOBLOCK, "DEBUG_LEVEL_INFOBLOCK\n" ); + debugPrint( DEBUG_LEVEL_TRANSFERS, "DEBUG_LEVEL_TRANSFERS\n" ); + + debugPrintShort( DEBUG_LEVEL_INFO, "DEBUG_LEVEL_INFO\n" ); + debugPrintShort( DEBUG_LEVEL_DEVICE, "DEBUG_LEVEL_DEVICE\n" ); + debugPrintShort( DEBUG_LEVEL_SUBUNIT, "DEBUG_LEVEL_SUBUNIT\n" ); + debugPrintShort( DEBUG_LEVEL_DESCRIPTOR, "DEBUG_LEVEL_DESCRIPTOR\n" ); + debugPrintShort( DEBUG_LEVEL_INFOBLOCK, "DEBUG_LEVEL_INFOBLOCK\n" ); + debugPrintShort( DEBUG_LEVEL_TRANSFERS, "DEBUG_LEVEL_TRANSFERS\n" ); + + debugError( "DEBUGERROR\n" ); + + // "Advance stuff" + debugError( "Wrong %s\n", "answer" ); + + debugPrint( DEBUG_LEVEL_INFOBLOCK, "The answer is %d\n", 42 ); + debugPrint( DEBUG_LEVEL_INFOBLOCK, "This %s test\n", "is a" ); + + + } + +protected: + DECLARE_DEBUG_MODULE; +}; + +int +main( int argc, char** argv ) +{ + TestDebugModule test; + + printf( "start...\n" ); + test.run(); + printf( "...done\n" ); + return 0; +} + +/* + * Local variables: + * compile-command: "g++ -DDEBUG -Wall -g -c ../src/debugmodule.cpp -I/usr/local/include && g++ -DDEBUG -Wall -g -c test_debug_module.cpp -I/usr/local/include && g++ -DDEBUG -Wall -g -o test_debug_module debugmodule.o test_debug_module.o" + * End: + */ Index: /branches/libfreebob-1.4/freebob/tests/avc_signal_source.h =================================================================== --- /branches/libfreebob-1.4/freebob/tests/avc_signal_source.h (revision 116) +++ /branches/libfreebob-1.4/freebob/tests/avc_signal_source.h (revision 116) @@ -0,0 +1,98 @@ +/* avc_signal_source.h + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#ifndef AVCSignalSource_h +#define AVCSignalSource_h + +#include "avc_generic.h" +#include "avc_definitions.h" + +#include + +class SignalAddress: public IBusData +{ +public: + enum EPlugId { + ePI_AnyAvailableSerialBusPlug = 0x7e, + ePI_Invalid = 0xfe, + ePI_AnyAvailableExternalPlug = 0xff, + }; +}; + +class SignalUnitAddress: public SignalAddress +{ +public: + SignalUnitAddress(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + virtual SignalUnitAddress* clone() const; + + byte_t m_plugId; +}; + +class SignalSubunitAddress: public SignalAddress +{ +public: + SignalSubunitAddress(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + virtual SignalSubunitAddress* clone() const; + + byte_t m_subunitType; + byte_t m_subunitId; + byte_t m_plugId; +}; + +class SignalSourceCmd: public AVCCommand +{ +public: + SignalSourceCmd(); + virtual ~SignalSourceCmd(); + + virtual bool serialize( IOSSerialize& se ); + virtual bool deserialize( IISDeserialize& de ); + + virtual bool fire( raw1394handle_t handle, + unsigned int node_id ); + + bool setSignalSource( SignalUnitAddress& signalAddress ); + bool setSignalSource( SignalSubunitAddress& signalAddress ); + bool setSignalDestination( SignalUnitAddress& signalAddress ); + bool setSignalDestination( SignalSubunitAddress& signalAddress ); + + SignalAddress* getSignalSource(); + SignalAddress* getSignalDestination(); + + // Control response + byte_t m_resultStatus; + + // Status response + byte_t m_outputStatus; + byte_t m_conv; + byte_t m_signalStatus; + + SignalAddress* m_signalSource; + SignalAddress* m_signalDestination; +}; + + +#endif // AVCSignalSource_h Index: /branches/libfreebob-1.4/freebob/tests/serialize.h =================================================================== --- /branches/libfreebob-1.4/freebob/tests/serialize.h (revision 108) +++ /branches/libfreebob-1.4/freebob/tests/serialize.h (revision 108) @@ -0,0 +1,91 @@ +/* serialize.h + * Copyright (C) 2005 by Daniel Wagner + * + * This file is part of FreeBob. + * + * FreeBob 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. + * FreeBob 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 FreeBob; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + */ + +#ifndef Serialize_h +#define Serialize_h + +#include // byte_t and quadlet_t declaration + +// Interfaces + +class IOSSerialize { +public: + virtual bool write( byte_t value, const char* name = "" ) = 0; + virtual bool write( quadlet_t value, const char* name = "" ) = 0; +}; + +class IISDeserialize { +public: + virtual bool read( byte_t* value ) = 0; + virtual bool read( quadlet_t* value ) = 0; + virtual bool peek( byte_t* value ) = 0; +}; + +// Specialized implementations of previously defined interfaces + +class CoutSerializer: public IOSSerialize { +public: + virtual bool write( byte_t value, const char* name = "" ); + virtual bool write( quadlet_t value, const char* name = "" ); +}; + +class BufferSerialize: public IOSSerialize { +public: + BufferSerialize( unsigned char* buffer, size_t length ) + : m_buffer( buffer ) + , m_curPos( m_buffer ) + , m_length( length ) + {} + + virtual bool write( byte_t value, const char* name = "" ); + virtual bool write( quadlet_t value, const char* name = "" ); + +protected: + inline bool isCurPosValid() const; + +private: + unsigned char* m_buffer; + unsigned char* m_curPos; + size_t m_length; +}; + +class BufferDeserialize: public IISDeserialize { +public: + BufferDeserialize( const unsigned char* buffer, size_t length ) + : m_buffer( const_cast( buffer ) ) + , m_curPos( m_buffer ) + , m_length( length ) + {} + + virtual bool read( byte_t* value ); + virtual bool read( quadlet_t* value ); + virtual bool peek( byte_t* value ); + +protected: + inline bool isCurPosValid() const; + +private: + unsigned char* m_buffer; // start of the buffer + unsigned char* m_curPos; // current read pos + size_t m_length; // length of buffer +}; + +#endif // Serialize_h + Index: /branches/libfreebob-1.4/freebob/configure.ac =================================================================== --- /branches/libfreebob-1.4/freebob/configure.ac (revision 79) +++ /branches/libfreebob-1.4/freebob/configure.ac (revision 79) @@ -0,0 +1,124 @@ +# configure.ac - Configure script for FreeBob. +# Copyright (C) 2004 by Daniel Wagner. +# +# This file is part of FreeBob. +# +# FreeBob 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. +# FreeBob 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 FreeBob; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(freebob, 0.1, ) +AM_INIT_AUTOMAKE +AM_MAINTAINER_MODE +AC_CONFIG_SRCDIR([src/main.cpp]) +AC_CONFIG_HEADER([config.h]) +AC_GNU_SOURCE +AC_LANG(C++) + +maintainer_mode=${enable_maintainer_mode-no} + +# Checks for programs. +AC_PROG_CC +AC_PROG_CXX +AM_PROG_AS +AC_PROG_RANLIB +AC_CHECK_TOOL([AR], [ar], :) +AC_CHECK_TOOL([NM], [nm], :) +AC_PATH_PROG([SED], [sed], :) +AC_PATH_PROG([SORT], [sort], :) + +# Required for building the documentation + +# Checks for libraries. +AC_CHECK_LIB(raw1394, raw1394_new_handle, , + [AC_MSG_ERROR([Unable to link with libraw1394. Check that you have libraw1394 installed])]) + +AC_CHECK_LIB(avc1394, avc1394_vcr_record, , + [AC_MSG_ERROR([Unable to link with libavc1394. Check that you have libavc1394 installed and that the version is 0.4.1 or newer])]) + +AC_CHECK_LIB(pthread, pthread_create,, +[ + AC_ERROR(You need the pthread library to compile freebob) +]) + +# Checks for header files. +AC_CHECK_HEADERS([libraw1394/raw1394.h], , + [AC_MSG_ERROR([raw1394.h not found install libraw1394-devel]) +]) + +AC_CHECK_HEADER([libavc1394/avc1394.h], , + [AC_MSG_ERROR([avc1394.h not found, install libavc1394-devel]) +]) +AC_CHECK_HEADER([libavc1394/rom1394.h], , + [AC_MSG_ERROR([rom1394.h not found, install libavc1394-devel]) +]) +AC_CHECK_HEADER(execinfo.h, [AC_DEFINE(HAVE_EXECINFO_H, 1, Wheter or not execinfo.h is present) + EXTRA_LIBS="$EXTRA_LIBS -rdynamic"]) + +# Check for libXML2 +PKG_CHECK_MODULES(LIBXML, libxml-2.0 >= 2.6.0) +AC_SUBST([LIBXML_LIBS]) +AC_SUBST([LIBXML_CFLAGS]) + +# Check for liblo +PKG_CHECK_MODULES(LIBLO, liblo >= 0.18) +AC_SUBST([LIBLO_LIBS]) +AC_SUBST([LIBLO_CFLAGS]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_CANONICAL_HOST +AC_C_CONST +AC_C_VOLATILE +CFLAGS="$CFLAGS -Wall -DDEBUG" # XXX DEBUG should not always be set +CXXFLAGS="$CXXFLAGS -Wall -DDEBUG" # XXX DEBUG should not always be set + +AC_SUBST([CFLAGS]) +AC_SUBST([CXXFLAGS]) + +# Configure components. + +# Create links for header file. + +# Checks for library functions. +PKG_CHECK_MODULES(LIBRAW1394, libraw1394 >= 1.1.0) +PKG_CHECK_MODULES(LIBIEC61883, libiec61883 >= 0.1.0) + +PKG_CHECK_MODULES(ALSA, alsa >= 1.0.0) + +AC_SUBST([LIBSIGC_CFLAGS]) +AC_SUBST([LIBSIGC_LIBS]) +AC_SUBST([LIBRAW1394_CFLAGS]) +AC_SUBST([LIBRAW1394_LIBS]) +AC_SUBST([LIBIEC61883_CFLAGS]) +AC_SUBST([LIBIEC61883_LIBS]) +AC_SUBST([ALSA_CFLAGS]) +AC_SUBST([ALSA_LIBS]) +LIBAVC_LIBS="-lrom1394 -lavc1394" +AC_SUBST([LIBAVC_LIBS]) + +AC_CONFIG_FILES([Makefile + src/Makefile + tests/Makefile]) +AC_OUTPUT + +# Print a summary so that important information isn't missed. +AC_MSG_RESULT([ + +FreeBob is now configured for $canonical_host_type + + Source directory: $srcdir + Installation prefix: $prefix + C++ compiler: $CXX $XTRA_CXXFLAGS $WARN_CXXFLAGS $CXXFLAGS +]) Index: /branches/libfreebob-1.4/freebob/AUTHORS =================================================================== --- /branches/libfreebob-1.4/freebob/AUTHORS (revision 4) +++ /branches/libfreebob-1.4/freebob/AUTHORS (revision 4) @@ -0,0 +1,1 @@ +Daniel Wagner Index: /branches/libfreebob-1.4/freebob/doc/freebob.xmi =================================================================== --- /branches/libfreebob-1.4/freebob/doc/freebob.xmi (revision 16) +++ /branches/libfreebob-1.4/freebob/doc/freebob.xmi (revision 16) @@ -0,0 +1,7152 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.2.0 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +