Changeset 199
- Timestamp:
- 05/17/06 02:57:45 (17 years ago)
- Files:
-
- branches/libfreebob-2.0/configure.ac (modified) (3 diffs)
- branches/libfreebob-2.0/libfreebob/freebob.h (modified) (1 diff)
- branches/libfreebob-2.0/src/bounce/bounce_avdevice.cpp (modified) (5 diffs)
- branches/libfreebob-2.0/src/bounce/bounce_avdevice.h (modified) (2 diffs)
- branches/libfreebob-2.0/src/configrom.cpp (modified) (1 diff)
- branches/libfreebob-2.0/src/configrom.h (modified) (1 diff)
- branches/libfreebob-2.0/src/devicemanager.cpp (modified) (4 diffs)
- branches/libfreebob-2.0/src/devicemanager.h (modified) (1 diff)
- branches/libfreebob-2.0/src/freebob.cpp (modified) (1 diff)
- branches/libfreebob-2.0/src/libfreebobstreaming/freebob_streaming.c (modified) (13 diffs)
- branches/libfreebob-2.0/src/libfreebobstreaming/freebob_streaming_private.h (modified) (1 diff)
- branches/libfreebob-2.0/src/libfreebobstreaming/handlers.c (added)
- branches/libfreebob-2.0/src/libfreebobstreaming/handlers.h (added)
- branches/libfreebob-2.0/src/libfreebobstreaming/Makefile.am (modified) (1 diff)
- branches/libfreebob-2.0/src/libfreebobstreaming/watchdog.c (added)
- branches/libfreebob-2.0/src/libfreebobstreaming/watchdog.h (added)
- branches/libfreebob-2.0/src/libstreaming (added)
- branches/libfreebob-2.0/src/libstreaming/debug.h (added)
- branches/libfreebob-2.0/src/libstreaming/FreebobAtomic.h (added)
- branches/libfreebob-2.0/src/libstreaming/FreebobPosixThread.cpp (added)
- branches/libfreebob-2.0/src/libstreaming/FreebobPosixThread.h (added)
- branches/libfreebob-2.0/src/libstreaming/FreebobThread.h (added)
- branches/libfreebob-2.0/src/libstreaming/freebob_streaming.c (added)
- branches/libfreebob-2.0/src/libstreaming/IsoHandler.cpp (added)
- branches/libfreebob-2.0/src/libstreaming/IsoHandler.h (added)
- branches/libfreebob-2.0/src/libstreaming/IsoHandlerManager.cpp (added)
- branches/libfreebob-2.0/src/libstreaming/IsoHandlerManager.h (added)
- branches/libfreebob-2.0/src/libstreaming/IsoStream.cpp (added)
- branches/libfreebob-2.0/src/libstreaming/IsoStream.h (added)
- branches/libfreebob-2.0/src/libstreaming/IsoStreamManager.cpp (added)
- branches/libfreebob-2.0/src/libstreaming/IsoStreamManager.h (added)
- branches/libfreebob-2.0/src/libstreaming/Makefile.am (added)
- branches/libfreebob-2.0/src/libstreaming/messagebuffer.c (added)
- branches/libfreebob-2.0/src/libstreaming/messagebuffer.h (added)
- branches/libfreebob-2.0/src/Makefile.am (modified) (3 diffs)
- branches/libfreebob-2.0/tests/freebob-server.c (modified) (10 diffs)
- branches/libfreebob-2.0/tests/test-freebob.c (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/libfreebob-2.0/configure.ac
r194 r199 22 22 AC_PREREQ(2.57) 23 23 24 m4_define(freebob_major_version, 0)25 m4_define(freebob_minor_version, 8)26 m4_define(freebob_micro_version, 2)24 m4_define(freebob_major_version, 1) 25 m4_define(freebob_minor_version, 1) 26 m4_define(freebob_micro_version, 0) 27 27 28 28 m4_define(freebob_version, freebob_major_version.freebob_minor_version.freebob_micro_version) … … 38 38 # - If the interface is the same as the previous version, change to C:R+1:A 39 39 40 LT_VERSION= 1:0:140 LT_VERSION=2:0:0 41 41 AC_SUBST(LT_VERSION) 42 42 … … 231 231 src/libfreebobavc/Makefile 232 232 src/libfreebobstreaming/Makefile 233 src/libstreaming/Makefile 233 234 src/Makefile 234 235 tests/Makefile branches/libfreebob-2.0/libfreebob/freebob.h
r185 r199 28 28 #define FREEBOB_BOUNCE_SERVER_VENDORNAME "FreeBoB Server" 29 29 #define FREEBOB_BOUNCE_SERVER_MODELNAME "freebob-server" 30 31 #define FREEBOB_BOUNCE_SERVER_GETXMLDESCRIPTION_CMD 32 #define AVC1394_SUBUNIT_TYPE_FREEBOB_BOUNCE_SERVER 0x0D 30 33 31 34 enum freebob_direction { branches/libfreebob-2.0/src/bounce/bounce_avdevice.cpp
r185 r199 30 30 #include <string> 31 31 #include <stdint.h> 32 #include <iostream> 33 #include <netinet/in.h> 32 34 33 35 namespace Bounce { … … 53 55 BounceDevice::~BounceDevice() 54 56 { 55 57 delete m_configRom; 56 58 } 57 59 … … 65 67 BounceDevice::discover() 66 68 { 67 std::string vendor = std::string(FREEBOB_BOUNCE_SERVER_VENDORNAME); 68 std::string model = std::string(FREEBOB_BOUNCE_SERVER_MODELNAME); 69 unsigned int resp_len=0; 70 quadlet_t request[6]; 71 quadlet_t *resp; 69 72 70 if (m_configRom->getVendorName().compare(0,vendor.length(),vendor,0,vendor.length())==0) { 71 if(m_configRom->getModelName().compare(0,model.length(),model,0,model.length())==0) { 72 return true; 73 } 74 } 75 return false; 73 std::string vendor=std::string(FREEBOB_BOUNCE_SERVER_VENDORNAME); 74 std::string model=std::string(FREEBOB_BOUNCE_SERVER_MODELNAME); 75 76 if (!(m_configRom->getVendorName().compare(0,vendor.length(),vendor,0,vendor.length())==0) 77 || !(m_configRom->getModelName().compare(0,model.length(),model,0,model.length())==0)) { 78 return false; 79 } 80 81 // AVC1394_COMMAND_INPUT_PLUG_SIGNAL_FORMAT 82 request[0] = htonl( AVC1394_CTYPE_STATUS | (AVC1394_SUBUNIT_TYPE_FREEBOB_BOUNCE_SERVER << 19) | (0 << 16) 83 | AVC1394_COMMAND_INPUT_PLUG_SIGNAL_FORMAT | 0x00); 84 85 request[1] = 0xFFFFFFFF; 86 resp = m_1394Service->transactionBlock( m_nodeId, 87 request, 88 2, 89 &resp_len ); 90 // hexDump((unsigned char *)request,6*4); 91 if(resp) { 92 char *buffer=(char *)&resp[1]; 93 xmlDescription=buffer; 94 // hexDump((unsigned char *)resp,6*4); 95 } 96 97 return true; 76 98 } 77 99 … … 86 108 { 87 109 printf( "\nI am the bouncedevice, the bouncedevice I am...\n" ); 88 printf( "Vendor : %s\n", m_configRom->getVendorName().c_str()); 89 printf( "Model : %s\n", m_configRom->getModelName().c_str()); 90 printf( "GUID : 0x%016llX\n", m_configRom->getGuid()); 110 printf( "Vendor : %s\n", m_configRom->getVendorName().c_str()); 111 printf( "Model : %s\n", m_configRom->getModelName().c_str()); 112 printf( "Node : %d\n", m_nodeId); 113 printf( "GUID : 0x%016llX\n", m_configRom->getGuid()); 114 printf( "ACV test response : %s\n", xmlDescription.c_str()); 91 115 printf( "\n" ); 92 116 } … … 95 119 BounceDevice::addXmlDescription( xmlNodePtr deviceNode ) 96 120 { 121 122 xmlDocPtr doc; 123 xmlNodePtr cur; 124 xmlNodePtr copy; 125 126 doc = xmlParseFile("freebob_bouncedevice.xml"); 127 128 if (doc == NULL ) { 129 debugError( "freebob_bouncedevice.xml not parsed successfully. \n"); 130 return false; 131 } 132 133 cur = xmlDocGetRootElement(doc); 134 135 if (cur == NULL) { 136 debugError( "empty document\n"); 137 xmlFreeDoc(doc); 138 return false; 139 } 140 141 if (xmlStrcmp(cur->name, (const xmlChar *) "FreeBobBounceDevice")) { 142 debugError( "document of the wrong type, root node != FreeBobBounceDevice\n"); 143 xmlFreeDoc(doc); 144 return false; 145 } 146 147 cur = cur->xmlChildrenNode; 148 while (cur != NULL) { 149 char *result; 150 151 copy=xmlCopyNode(cur,1); 152 153 // debugOutput(DEBUG_LEVEL_NORMAL,"copying %s\n",cur->name); 154 155 156 if (!copy || !xmlAddChild(deviceNode, copy)) { 157 debugError( "could not add child node\n"); 158 cur = cur->next; 159 continue; 160 } 161 162 // add the node id 163 // if (xmlStrcmp(copy->name, (const xmlChar *) "ConnectionSet")) { 164 // asprintf( &result, "%d", m_nodeId); 165 // if ( !xmlNewChild( copy, 0, 166 // BAD_CAST "Node", BAD_CAST result ) ) { 167 // debugError( "Couldn't create 'Node' node\n" ); 168 // return false; 169 // free(result); 170 // } 171 // free(result); 172 // } 173 174 cur = cur->next; 175 } 176 177 xmlFreeDoc(doc); 178 97 179 return true; 98 180 } branches/libfreebob-2.0/src/bounce/bounce_avdevice.h
r185 r199 29 29 #include "libfreebobavc/avc_extended_cmd_generic.h" 30 30 #include "libfreebob/xmlparser.h" 31 #include "libfreebob/freebob_bounce.h" 31 32 32 33 class ConfigRom; … … 54 55 int m_verboseLevel; 55 56 57 private: 58 std::string xmlDescription; 59 60 56 61 DECLARE_DEBUG_MODULE; 57 62 }; branches/libfreebob-2.0/src/configrom.cpp
r185 r199 354 354 return m_vendorName; 355 355 } 356 357 const unsigned int 358 ConfigRom::getModelId() const 359 { 360 return m_modelId; 361 } 362 363 const unsigned int 364 ConfigRom::getVendorId() const 365 { 366 return m_vendorId; 367 } branches/libfreebob-2.0/src/configrom.h
r185 r199 44 44 const std::string getModelName() const; 45 45 const std::string getVendorName() const; 46 46 const unsigned int getModelId() const; 47 const unsigned int getVendorId() const; 47 48 48 49 protected: branches/libfreebob-2.0/src/devicemanager.cpp
r188 r199 30 30 #include "bebob_light/bebob_light_avdevice.h" 31 31 #include "bounce/bounce_avdevice.h" 32 #include "motu/motu_avdevice.h" 32 33 33 34 #include <iostream> … … 40 41 : m_1394Service( 0 ) 41 42 { 42 m_probeList.push_back( probeBeBoB ); 43 m_probeList.push_back( probeBounce ); 43 m_probeList.push_back( probeMotu ); 44 m_probeList.push_back( probeBeBoB ); 45 m_probeList.push_back( probeBounce ); 44 46 } 45 47 … … 137 139 IAvDevice* avDevice = new BeBoB_Light::AvDevice( service, id, level ); 138 140 if ( !avDevice ) { 139 return 0;141 return NULL; 140 142 } 141 143 142 144 if ( !avDevice->discover() ) { 143 145 delete avDevice; 144 return 0;146 return NULL; 145 147 } 146 148 return avDevice; … … 152 154 IAvDevice* avDevice = new Bounce::BounceDevice( service, id, level ); 153 155 if ( !avDevice ) { 154 return 0;156 return NULL; 155 157 } 156 158 157 159 if ( !avDevice->discover() ) { 158 160 delete avDevice; 159 return 0; 161 return NULL; 162 } 163 return avDevice; 164 } 165 166 IAvDevice* 167 DeviceManager::probeMotu(Ieee1394Service& service, int id, int level) 168 { 169 IAvDevice* avDevice = new Motu::MotuDevice( service, id, level ); 170 if ( !avDevice ) { 171 return NULL; 172 } 173 174 if ( !avDevice->discover() ) { 175 delete avDevice; 176 return NULL; 160 177 } 161 178 return avDevice; branches/libfreebob-2.0/src/devicemanager.h
r185 r199 59 59 static IAvDevice* probeBeBoB(Ieee1394Service& service, int id, int level); 60 60 static IAvDevice* probeBounce(Ieee1394Service& service, int id, int level); 61 static IAvDevice* probeMotu(Ieee1394Service& service, int id, int level); 61 62 62 63 protected: branches/libfreebob-2.0/src/freebob.cpp
r186 r199 1 /* freebob. h1 /* freebob.cpp 2 2 * Copyright (C) 2005 Pieter Palmers, Daniel Wagner 3 3 * branches/libfreebob-2.0/src/libfreebobstreaming/freebob_streaming.c
r194 r199 39 39 #include "thread.h" 40 40 #include "messagebuffer.h" 41 #include "watchdog.h" 42 #include "handlers.h" 41 43 42 44 #include <signal.h> 43 45 #include <unistd.h> 44 46 45 /**46 * Callbacks47 */48 49 static enum raw1394_iso_disposition50 iso_slave_receive_handler(raw1394handle_t handle, unsigned char *data,51 unsigned int length, unsigned char channel,52 unsigned char tag, unsigned char sy, unsigned int cycle,53 unsigned int dropped);54 55 static enum raw1394_iso_disposition56 iso_master_receive_handler(raw1394handle_t handle, unsigned char *data,57 unsigned int length, unsigned char channel,58 unsigned char tag, unsigned char sy, unsigned int cycle,59 unsigned int dropped);60 61 static enum raw1394_iso_disposition62 iso_slave_transmit_handler(raw1394handle_t handle,63 unsigned char *data, unsigned int *length,64 unsigned char *tag, unsigned char *sy,65 int cycle, unsigned int dropped);66 67 static enum raw1394_iso_disposition68 iso_master_transmit_handler(raw1394handle_t handle,69 unsigned char *data, unsigned int *length,70 unsigned char *tag, unsigned char *sy,71 int cycle, unsigned int dropped);72 73 47 static int freebob_am824_recv(char *data, 74 48 int nevents, unsigned int offset, unsigned int dbc, … … 1944 1918 } 1945 1919 1946 inline int freebob_streaming_decode_midi(freebob_connection_t *connection,1947 quadlet_t* events,1948 unsigned int nsamples,1949 unsigned int dbc1950 ) {1951 quadlet_t *target_event;1952 1953 assert (connection);1954 assert (events);1955 1956 freebob_stream_t *stream;1957 1958 unsigned int j=0;1959 unsigned int s=0;1960 int written=0;1961 quadlet_t *buffer;1962 1963 for (s=0;s<connection->nb_streams;s++) {1964 stream=&connection->streams[s];1965 1966 assert (stream);1967 assert (stream->spec.position < connection->spec.dimension);1968 assert(stream->user_buffer);1969 1970 if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {1971 /* idea:1972 spec says: current_midi_port=(dbc+j)%8;1973 => if we start at (dbc+stream->location-1)%8 [due to location_min=1],1974 we'll start at the right event for the midi port.1975 => if we increment j with 8, we stay at the right event.1976 */1977 buffer=((quadlet_t *)(stream->user_buffer));1978 written=0;1979 1980 for(j = (dbc & 0x07)+stream->spec.location-1; j < nsamples; j += 8) {1981 target_event=(quadlet_t *)(events + ((j * connection->spec.dimension) + stream->spec.position));1982 quadlet_t sample_int=ntohl(*target_event);1983 if(IEC61883_AM824_GET_LABEL(sample_int) != IEC61883_AM824_LABEL_MIDI_NO_DATA) {1984 *(buffer)=(sample_int >> 16);1985 buffer++;1986 written++;1987 }1988 }1989 1990 int written_to_rb=freebob_ringbuffer_write(stream->buffer, (char *)(stream->user_buffer), written*sizeof(quadlet_t))/sizeof(quadlet_t);1991 if(written_to_rb<written) {1992 printMessage("MIDI OUT bytes lost (%d/%d)",written_to_rb,written);1993 }1994 }1995 }1996 return 0;1997 1998 }1999 2000 /*2001 * according to the MIDI over 1394 spec, we are only allowed to send a maximum of one midi byte every 320usec2002 * therefore we can only send one byte on 1 out of 3 iso cycles (=325usec)2003 */2004 2005 inline int freebob_streaming_encode_midi(freebob_connection_t *connection,2006 quadlet_t* events,2007 unsigned int nsamples,2008 unsigned int dbc2009 ) {2010 quadlet_t *target_event;2011 2012 assert (connection);2013 assert (events);2014 2015 freebob_stream_t *stream;2016 2017 unsigned int j=0;2018 unsigned int s=0;2019 int read=0;2020 quadlet_t *buffer;2021 2022 for (s=0;s<connection->nb_streams;s++) {2023 stream=&connection->streams[s];2024 2025 assert (stream);2026 assert (stream->spec.position < connection->spec.dimension);2027 assert(stream->user_buffer);2028 2029 if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {2030 // first prefill the buffer with NO_DATA's on all time muxed channels2031 for(j=0; (j < nsamples); j++) {2032 target_event=(quadlet_t *)(events + ((j * connection->spec.dimension) + stream->spec.position));2033 2034 *target_event=htonl(IEC61883_AM824_SET_LABEL(0,IEC61883_AM824_LABEL_MIDI_NO_DATA));2035 2036 }2037 2038 /* idea:2039 spec says: current_midi_port=(dbc+j)%8;2040 => if we start at (dbc+stream->location-1)%8 [due to location_min=1],2041 we'll start at the right event for the midi port.2042 => if we increment j with 8, we stay at the right event.2043 */2044 2045 if(stream->midi_counter<=0) { // we can send a byte2046 read=freebob_ringbuffer_read(stream->buffer, (char *)(stream->user_buffer), 1*sizeof(quadlet_t))/sizeof(quadlet_t);2047 if(read) {2048 // j = (dbc%8)+stream->spec.location-1;2049 j = (dbc & 0x07)+stream->spec.location-1;2050 target_event=(quadlet_t *)(events + ((j * connection->spec.dimension) + stream->spec.position));2051 buffer=((quadlet_t *)(stream->user_buffer));2052 2053 *target_event=htonl(IEC61883_AM824_SET_LABEL((*buffer)<<16,IEC61883_AM824_LABEL_MIDI_1X));2054 stream->midi_counter=3; // only if we send a byte, we reset the counter2055 }2056 } else {2057 stream->midi_counter--;2058 }2059 }2060 }2061 return 0;2062 2063 }2064 2065 2066 /**2067 * ISO send/receive callback handlers2068 */2069 2070 static enum raw1394_iso_disposition2071 iso_master_receive_handler(raw1394handle_t handle, unsigned char *data,2072 unsigned int length, unsigned char channel,2073 unsigned char tag, unsigned char sy, unsigned int cycle,2074 unsigned int dropped)2075 {2076 enum raw1394_iso_disposition retval=RAW1394_ISO_OK;2077 2078 freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);2079 assert(connection);2080 2081 struct iec61883_packet *packet = (struct iec61883_packet *) data;2082 assert(packet);2083 2084 // FIXME: dropped packets are very bad when transmitting and the other side is sync'ing on that!2085 connection->status.dropped+=dropped;2086 2087 #ifdef DEBUG2088 connection->status.last_cycle=cycle;2089 #endif2090 2091 if((packet->fmt == 0x10) && (packet->fdf != 0xFF) && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) {2092 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;2093 2094 // add the data payload to the ringbuffer2095 2096 assert(connection->spec.dimension == packet->dbs);2097 2098 if (freebob_ringbuffer_write(2099 connection->event_buffer,(char *)(data+8),2100 nevents*sizeof(quadlet_t)*connection->spec.dimension) <2101 nevents*sizeof(quadlet_t)*connection->spec.dimension)2102 {2103 printError("MASTER RCV: Buffer overrun!\n");2104 connection->status.xruns++;2105 retval=RAW1394_ISO_DEFER;2106 } else {2107 retval=RAW1394_ISO_OK;2108 // we cannot offload midi encoding due to the need for a dbc value2109 freebob_streaming_decode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);2110 }2111 2112 // keep the frame counter2113 connection->status.frames_left -= nevents;2114 2115 // keep track of the total amount of events received2116 connection->status.events+=nevents;2117 2118 #ifdef DEBUG2119 connection->status.fdf=packet->fdf;2120 #endif2121 2122 } else {2123 // discard packet2124 // can be important for sync though2125 }2126 2127 // one packet received2128 connection->status.packets++;2129 2130 if(packet->dbs) {2131 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;2132 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,2133 "MASTER RCV: %08d, CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %4d, info->packets=%4d, events=%4d, %d, %d\n",2134 cycle,2135 channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, length,2136 ((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,2137 connection->status.packets, connection->status.events, connection->status.frames_left,2138 nevents);2139 }2140 2141 if((connection->status.frames_left<=0)) {2142 connection->pfd->events=0;2143 return RAW1394_ISO_DEFER;2144 }2145 2146 return retval;2147 }2148 2149 2150 static enum raw1394_iso_disposition2151 iso_slave_receive_handler(raw1394handle_t handle, unsigned char *data,2152 unsigned int length, unsigned char channel,2153 unsigned char tag, unsigned char sy, unsigned int cycle,2154 unsigned int dropped)2155 {2156 enum raw1394_iso_disposition retval=RAW1394_ISO_OK;2157 /* slave receive is easy if you assume that the connections are synced2158 Synced connections have matched data rates, so just receiving and2159 calling the rcv handler would suffice in this case. As the connection2160 is externally matched to the master connection, the buffer fill will be ok.2161 */2162 /* TODO: implement correct SYT behaviour */2163 2164 freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);2165 assert(connection);2166 2167 struct iec61883_packet *packet = (struct iec61883_packet *) data;2168 assert(packet);2169 2170 // FIXME: dropped packets are very bad when transmitting and the other side is sync'ing on that!2171 //connection->status.packets+=dropped;2172 connection->status.dropped+=dropped;2173 2174 #ifdef DEBUG2175 connection->status.last_cycle=cycle;2176 #endif2177 2178 if((packet->fmt == 0x10) && (packet->fdf != 0xFF) && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) {2179 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;2180 2181 #ifdef DEBUG2182 connection->status.fdf=packet->fdf;2183 #endif2184 2185 // add the data payload to the ringbuffer2186 2187 assert(connection->spec.dimension == packet->dbs);2188 2189 if (freebob_ringbuffer_write(2190 connection->event_buffer,(char *)(data+8),2191 nevents*sizeof(quadlet_t)*connection->spec.dimension) <2192 nevents*sizeof(quadlet_t)*connection->spec.dimension)2193 {2194 printError("SLAVE RCV: Buffer overrun!\n");2195 connection->status.xruns++;2196 retval=RAW1394_ISO_DEFER;2197 } else {2198 retval=RAW1394_ISO_OK;2199 // we cannot offload midi encoding due to the need for a dbc value2200 freebob_streaming_decode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);2201 }2202 2203 connection->status.frames_left-=nevents;2204 2205 // keep track of the total amount of events received2206 connection->status.events+=nevents;2207 } else {2208 // discard packet2209 // can be important for sync though2210 }2211 2212 // one packet received2213 connection->status.packets++;2214 2215 if(packet->dbs) {2216 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,2217 "SLAVE RCV: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n",2218 channel, packet->fdf,2219 packet->syt,2220 packet->dbs,2221 packet->dbc,2222 packet->fmt,2223 length,2224 ((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped);2225 }2226 2227 2228 if((connection->status.frames_left<=0)) {2229 connection->pfd->events=0;2230 return RAW1394_ISO_DEFER;2231 }2232 2233 return retval;2234 }2235 2236 /**2237 * The master transmit handler.2238 *2239 * This is the most difficult, because we have to generate timing information ourselves.2240 *2241 */2242 2243 /*2244 Includes code from libiec618832245 */2246 static enum raw1394_iso_disposition2247 iso_master_transmit_handler(raw1394handle_t handle,2248 unsigned char *data, unsigned int *length,2249 unsigned char *tag, unsigned char *sy,2250 int cycle, unsigned int dropped)2251 {2252 freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);2253 assert(connection);2254 2255 struct iec61883_packet *packet = (struct iec61883_packet *) data;2256 assert(packet);2257 assert(length);2258 assert(tag);2259 assert(sy);2260 2261 // construct the packet cip2262 int nevents = iec61883_cip_fill_header (handle, &connection->status.cip, packet);2263 int nsamples=0;2264 int bytes_read;2265 2266 #ifdef DEBUG2267 connection->status.last_cycle=cycle;2268 2269 if(packet->fdf != 0xFF) {2270 connection->status.fdf=packet->fdf;2271 }2272 #endif2273 2274 enum raw1394_iso_disposition retval = RAW1394_ISO_OK;2275 2276 2277 2278 if (nevents > 0) {2279 nsamples = nevents;2280 }2281 else {2282 if (connection->status.cip.mode == IEC61883_MODE_BLOCKING_EMPTY) {2283 nsamples = 0;2284 }2285 else {2286 nsamples = connection->status.cip.syt_interval;2287 }2288 }2289 2290 // dropped packets are very bad when transmitting and the other side is sync'ing on that!2291 connection->status.dropped += dropped;2292 2293 if (nsamples > 0) {2294 2295 assert(connection->spec.dimension == packet->dbs);2296 2297 if ((bytes_read=freebob_ringbuffer_read(connection->event_buffer,(char *)(data+8),nsamples*sizeof(quadlet_t)*connection->spec.dimension)) <2298 nsamples*sizeof(quadlet_t)*connection->spec.dimension)2299 {2300 printError("MASTER XMT: Buffer underrun! (%d / %d) (%d / %d )\n",2301 bytes_read,nsamples*sizeof(quadlet_t)*connection->spec.dimension,2302 freebob_ringbuffer_read_space(connection->event_buffer),0);2303 connection->status.xruns++;2304 retval=RAW1394_ISO_DEFER;2305 nsamples=0;2306 } else {2307 retval=RAW1394_ISO_OK;2308 // we cannot offload midi encoding due to the need for a dbc value2309 freebob_streaming_encode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);2310 }2311 }2312 2313 *length = nsamples * connection->spec.dimension * sizeof (quadlet_t) + 8;2314 *tag = IEC61883_TAG_WITH_CIP;2315 *sy = 0;2316 2317 // keep track of the total amount of events transmitted2318 connection->status.events+=nsamples;2319 2320 connection->status.frames_left-=nsamples;2321 2322 // one packet transmitted2323 connection->status.packets++;2324 2325 if(packet->dbs) {2326 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,2327 "MASTER XMT: %08d, CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %4d, info->packets=%4d, events=%4d, %d, %d %d\n", cycle,2328 connection->iso.iso_channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,((*length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,2329 connection->status.packets, connection->status.events, connection->status.frames_left,2330 nevents, nsamples);2331 }2332 2333 if((connection->status.frames_left<=0)) {2334 connection->pfd->events=0;2335 return RAW1394_ISO_DEFER;2336 }2337 2338 return retval;2339 2340 }2341 2342 static enum raw1394_iso_disposition2343 iso_slave_transmit_handler(raw1394handle_t handle,2344 unsigned char *data, unsigned int *length,2345 unsigned char *tag, unsigned char *sy,2346 int cycle, unsigned int dropped)2347 {2348 freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);2349 assert(connection);2350 2351 struct iec61883_packet *packet = (struct iec61883_packet *) data;2352 assert(packet);2353 assert(length);2354 assert(tag);2355 assert(sy);2356 2357 // construct the packet cip2358 struct iec61883_cip old_cip;2359 memcpy(&old_cip,&connection->status.cip,sizeof(struct iec61883_cip));2360 2361 int nevents = iec61883_cip_fill_header (handle, &connection->status.cip, packet);2362 int nsamples=0;2363 int bytes_read;2364 2365 #ifdef DEBUG2366 connection->status.last_cycle=cycle;2367 2368 if(packet->fdf != 0xFF) {2369 connection->status.fdf=packet->fdf;2370 }2371 #endif2372 2373 enum raw1394_iso_disposition retval = RAW1394_ISO_OK;2374 2375 2376 if (nevents > 0) {2377 nsamples = nevents;2378 }2379 else {2380 if (connection->status.cip.mode == IEC61883_MODE_BLOCKING_EMPTY) {2381 nsamples = 0;2382 }2383 else {2384 nsamples = connection->status.cip.syt_interval;2385 }2386 }2387 2388 // dropped packets are very bad when transmitting and the other side is sync'ing on that!2389 //connection->status.packets+=dropped;2390 connection->status.dropped += dropped;2391 2392 if (nsamples > 0) {2393 int bytes_to_read=nsamples*sizeof(quadlet_t)*connection->spec.dimension;2394 2395 assert(connection->spec.dimension == packet->dbs);2396 2397 if ((bytes_read=freebob_ringbuffer_read(connection->event_buffer,(char *)(data+8),bytes_to_read)) <2398 bytes_to_read)2399 {2400 /* there is no more data in the ringbuffer */2401 2402 /* If there are already more than on period2403 * of frames transfered to the XMIT buffer, there is no xrun.2404 *2405 */2406 if(connection->status.frames_left<=0) {2407 // we stop processing this untill the next period boundary2408 // that's when new data is ready2409 2410 connection->pfd->events=0;2411 2412 // reset the cip to the old value2413 memcpy(&connection->status.cip,&old_cip,sizeof(struct iec61883_cip));2414 2415 // retry this packed2416 retval=RAW1394_ISO_AGAIN;2417 nsamples=0;2418 } else {2419 printError("SLAVE XMT : Buffer underrun! %d (%d / %d) (%d / %d )\n",2420 connection->status.frames_left, bytes_read,bytes_to_read,2421 freebob_ringbuffer_read_space(connection->event_buffer),0);2422 connection->status.xruns++;2423 retval=RAW1394_ISO_DEFER;2424 nsamples=0;2425 }2426 } else {2427 retval=RAW1394_ISO_OK;2428 // we cannot offload midi encoding due to the need for a dbc value2429 freebob_streaming_encode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);2430 }2431 }2432 2433 *length = nsamples * connection->spec.dimension * sizeof (quadlet_t) + 8;2434 *tag = IEC61883_TAG_WITH_CIP;2435 *sy = 0;2436 2437 // keep track of the total amount of events transmitted2438 connection->status.events+=nsamples;2439 2440 connection->status.frames_left-=nsamples;2441 2442 // one packet transmitted2443 connection->status.packets++;2444 2445 if(packet->dbs) {2446 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,2447 "SLAVE XMT : %08d, CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %4d, info->packets=%4d, events=%4d, %d, %d %d\n", cycle,2448 connection->iso.iso_channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,((*length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,2449 connection->status.packets, connection->status.events, connection->status.frames_left,2450 nevents, nsamples);2451 }2452 2453 if((connection->status.frames_left<=0)) {2454 connection->pfd->events=0;2455 return RAW1394_ISO_DEFER;2456 }2457 2458 return retval;2459 2460 }2461 1920 2462 1921 /* … … 2795 2254 case freebob_buffer_type_per_stream: 2796 2255 default: 2797 // assert(nsamples < dev->options.period_size);2798 2799 2256 // use the preallocated buffer (at init time) 2800 2257 buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position; … … 2828 2285 for(j = 0; j < nsamples; j += 1) { // decode max nsamples 2829 2286 *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF); 2830 // fprintf(stderr,"[%03d, %02d: %08p %08X %08X]\n",j, stream->spec.position, target_event, *target_event, *buffer);2831 2287 buffer++; 2832 2288 target_event+=dimension; … … 2848 2304 } 2849 2305 2850 // fprintf(stderr,"rb write [%02d: %08p %08p]\n",stream->spec.position, stream, stream->buffer);2851 2852 // fprintf(stderr,"rb write [%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);2853 2306 if(do_ringbuffer_write) { 2854 2307 // reset the buffer pointer … … 2858 2311 written=nsamples; 2859 2312 } 2860 2861 // fprintf(stderr,"rb write1[%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written); 2313 2862 2314 2863 2315 return written; … … 2872 2324 2873 2325 return 0; 2874 2875 2326 2876 2327 } … … 2884 2335 ) { 2885 2336 quadlet_t *target_event; 2886 //freebob_sample_t buff[nsamples];2887 2337 int do_ringbuffer_read=0; 2888 2338 … … 2904 2354 case freebob_buffer_type_per_stream: 2905 2355 default: 2906 // assert(nsamples < dev->options.period_size);2907 2356 // use the preallocated buffer (at init time) 2908 2357 buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position; … … 2923 2372 break; 2924 2373 } 2925 2926 2374 2927 2375 if(stream->spec.format == IEC61883_STREAM_TYPE_MBLA) { // MBLA … … 2942 2390 buffer++; 2943 2391 target_event+=dimension; 2944 2945 // fprintf(stderr,"[%03d, %02d: %08p %08X %08X]\n",j, stream->spec.position, target_event, *target_event, *buffer);2946 2947 2392 } 2948 2393 break; … … 2960 2405 } 2961 2406 2962 /*2963 for(j = 0; j < nsamples; j+=1) {2964 *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);2965 buffer++;2966 target_event+=connection->spec.dimension;2967 }2968 */2969 2970 2407 return read; 2971 2408 … … 3065 2502 return xrun; 3066 2503 } 3067 3068 void *freebob_streaming_watchdog_thread (void *arg)3069 {3070 freebob_device_t *dev = (freebob_device_t *) arg;3071 3072 dev->watchdog_check = 0;3073 3074 while (1) {3075 sleep (2);3076 if (dev->watchdog_check == 0) {3077 3078 printError("watchdog: timeout");3079 3080 /* kill our process group, try to get a dump */3081 kill (-getpgrp(), SIGABRT);3082 /*NOTREACHED*/3083 exit (1);3084 }3085 dev->watchdog_check = 0;3086 }3087 }3088 3089 int freebob_streaming_start_watchdog (freebob_device_t *dev)3090 {3091 int watchdog_priority = dev->packetizer.priority + 10;3092 int max_priority = sched_get_priority_max (SCHED_FIFO);3093 3094 debugPrint(DEBUG_LEVEL_STARTUP, "Starting Watchdog...\n");3095 3096 if ((max_priority != -1) &&3097 (max_priority < watchdog_priority))3098 watchdog_priority = max_priority;3099 3100 if (freebob_streaming_create_thread (dev, &dev->watchdog_thread, watchdog_priority,3101 TRUE, freebob_streaming_watchdog_thread, dev)) {3102 printError ("cannot start watchdog thread");3103 return -1;3104 }3105 3106 return 0;3107 }3108 3109 void freebob_streaming_stop_watchdog (freebob_device_t *dev)3110 {3111 debugPrint(DEBUG_LEVEL_STARTUP, "Stopping Watchdog...\n");3112 3113 pthread_cancel (dev->watchdog_thread);3114 pthread_join (dev->watchdog_thread, NULL);3115 }branches/libfreebob-2.0/src/libfreebobstreaming/freebob_streaming_private.h
r185 r199 188 188 void * freebob_iso_packet_iterator(void *arg); 189 189 190 void *freebob_streaming_watchdog_thread (void *arg);191 int freebob_streaming_start_watchdog (freebob_device_t *dev);192 void freebob_streaming_stop_watchdog (freebob_device_t *dev);193 194 190 void freebob_streaming_print_bufferfill(freebob_device_t *dev); 195 191 branches/libfreebob-2.0/src/libfreebobstreaming/Makefile.am
r192 r199 23 23 freebob_connections.c ringbuffer.c thread.c \ 24 24 cip.h freebob_connections.h messagebuffer.h \ 25 ringbuffer.h freebob_streaming_private.h freebob_debug.h thread.h 25 ringbuffer.h freebob_streaming_private.h freebob_debug.h thread.h \ 26 watchdog.c watchdog.h handlers.c handlers.h 26 27 27 28 INCLUDES = $(LIBRAW1394_CFLAGS) $(LIBIEC61883_CFLAGS) -I$(top_srcdir)/src \ branches/libfreebob-2.0/src/Makefile.am
r188 r199 17 17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 19 SUBDIRS = debugmodule libfreebobavc lib freebobstreaming19 SUBDIRS = debugmodule libfreebobavc libstreaming 20 20 21 21 INCLUDES = $(LIBSIGC_CFLAGS) $(LIBRAW1394_CFLAGS) $(LIBIEC61883_CFLAGS) \ … … 52 52 bebob_light/bebob_light_avplug.cpp \ 53 53 bounce/bounce_avdevice.h \ 54 bounce/bounce_avdevice.cpp 54 bounce/bounce_avdevice.cpp \ 55 motu/motu_avdevice.h \ 56 motu/motu_avdevice.cpp 55 57 56 58 libfreebob_la_LDFLAGS = -version-info $(LT_VERSION) -lpthread $(LIBSIGC_LIBS) \ … … 59 61 60 62 libfreebob_la_LIBADD = debugmodule/libdebugmodule.la libfreebobavc/libfreebobavc.la \ 61 lib freebobstreaming/libfreebobstreaming.la63 libstreaming/libstreaming.la 62 64 63 branches/libfreebob-2.0/tests/freebob-server.c
r185 r199 37 37 #include <libavc1394/rom1394.h> 38 38 39 #include "../libfreebob/freebob.h" 40 #include "../libfreebob/freebob_bounce.h" 41 39 42 const char not_compatible[] = "\n" 40 43 "This libraw1394 does not work with your version of Linux. You need a different\n" … … 47 50 48 51 49 unsigned char g_signal_mode = 0x05; // SD 525-60, TODO: get from media50 unsigned char g_transport_mode = AVC1394_VCR_CMD_WIND;51 unsigned char g_transport_state = AVC1394_VCR_OPERAND_WIND_STOP;52 53 52 static int g_done = 0; 54 53 … … 64 63 switch ( cr->opcode ) 65 64 { 66 case AVC1394_VCR_CMD_PLAY: 67 switch ( cr->operand[0] ) 68 { 69 case AVC1394_VCR_OPERAND_PLAY_FORWARD: 70 g_transport_mode = AVC1394_GET_OPCODE( AVC1394_VCR_RESPONSE_TRANSPORT_STATE_PLAY ); 71 g_transport_state = AVC1394_VCR_OPERAND_PLAY_FORWARD; 72 cr->status = AVC1394_RESP_ACCEPTED; 73 printf("PLAY FORWARD\n"); 74 break; 65 default: 66 fprintf( stderr, "subunit control command 0x%02x non supported\n", cr->opcode ); 67 return 0; 68 } 69 return 1; 70 } 71 72 int subunit_status( avc1394_cmd_rsp *cr ) 73 { 74 75 fprintf( stderr, "subunit STATUS\n"); 76 char *buffer; 77 switch ( cr->opcode ) 78 { 79 case (AVC1394_CMD_INPUT_PLUG_SIGNAL_FORMAT): 80 81 cr->status = AVC1394_RESP_STABLE; 82 buffer=(char*)&cr->operand[1]; 83 fprintf( stderr, "subunit AVC1394_COMMAND_INPUT_PLUG_SIGNAL_FORMAT\n"); 75 84 76 case AVC1394_VCR_OPERAND_PLAY_FASTEST_FORWARD: 77 g_transport_mode = AVC1394_GET_OPCODE( AVC1394_VCR_RESPONSE_TRANSPORT_STATE_PLAY ); 78 g_transport_state = AVC1394_VCR_OPERAND_PLAY_FASTEST_FORWARD; 79 cr->status = AVC1394_RESP_ACCEPTED; 80 printf("PLAY FASTEST FORWARD\n"); 81 break; 82 83 case AVC1394_VCR_OPERAND_PLAY_REVERSE_PAUSE: 84 g_transport_mode = AVC1394_GET_OPCODE( AVC1394_VCR_RESPONSE_TRANSPORT_STATE_PLAY ); 85 g_transport_state = cr->operand[0]; 86 cr->status = AVC1394_RESP_ACCEPTED; 87 printf("PAUSE PLAY\n"); 88 break; 89 90 case AVC1394_VCR_OPERAND_PLAY_REVERSE: 91 g_transport_mode = AVC1394_GET_OPCODE( AVC1394_VCR_RESPONSE_TRANSPORT_STATE_PLAY ); 92 g_transport_state = AVC1394_VCR_OPERAND_PLAY_REVERSE; 93 cr->status = AVC1394_RESP_ACCEPTED; 94 printf("PLAY REVERSE\n"); 95 break; 96 97 case AVC1394_VCR_OPERAND_PLAY_FASTEST_REVERSE: 98 g_transport_mode = AVC1394_GET_OPCODE( AVC1394_VCR_RESPONSE_TRANSPORT_STATE_PLAY ); 99 g_transport_state = AVC1394_VCR_OPERAND_PLAY_FASTEST_REVERSE; 100 cr->status = AVC1394_RESP_ACCEPTED; 101 printf("PLAY FASTEST REVERSE\n"); 102 break; 103 104 case AVC1394_VCR_OPERAND_PLAY_NEXT_FRAME: 105 g_transport_mode = AVC1394_GET_OPCODE( AVC1394_VCR_RESPONSE_TRANSPORT_STATE_PLAY ); 106 g_transport_state = cr->operand[0]; 107 cr->status = AVC1394_RESP_ACCEPTED; 108 printf("PLAY NEXT FRAME\n"); 109 break; 110 111 case AVC1394_VCR_OPERAND_PLAY_PREVIOUS_FRAME: 112 g_transport_mode = AVC1394_GET_OPCODE( AVC1394_VCR_RESPONSE_TRANSPORT_STATE_PLAY ); 113 g_transport_state = cr->operand[0]; 114 cr->status = AVC1394_RESP_ACCEPTED; 115 printf("PLAY PREVIOUS FRAME\n"); 116 break; 117 118 default: 119 fprintf( stderr, "play mode 0x%02x non supported\n", cr->operand[0] ); 120 return 0; 121 } 85 strncpy(buffer,"TEST123",sizeof(byte_t)*9); 122 86 break; 123 124 default:125 fprintf( stderr, "subunit control command 0x%02x non supported\n", cr->opcode );126 return 0;127 }128 return 1;129 }130 131 132 int subunit_status( avc1394_cmd_rsp *cr )133 {134 switch ( cr->opcode )135 {136 case AVC1394_VCR_CMD_OUTPUT_SIGNAL_MODE:137 cr->status = AVC1394_RESP_STABLE;138 cr->operand[0] = g_signal_mode;139 break;140 87 default: 141 88 fprintf( stderr, "subunit status command 0x%02x not supported\n", cr->opcode ); … … 150 97 switch ( cr->opcode ) 151 98 { 152 case AVC1394_VCR_CMD_PLAY:153 case AVC1394_VCR_CMD_RECORD:154 case AVC1394_VCR_CMD_WIND:155 case AVC1394_VCR_CMD_OUTPUT_SIGNAL_MODE:156 case AVC1394_VCR_CMD_INPUT_SIGNAL_MODE:157 case AVC1394_VCR_CMD_TRANSPORT_STATE:158 case AVC1394_VCR_CMD_TIME_CODE:159 case AVC1394_VCR_CMD_MEDIUM_INFO:160 cr->status = AVC1394_RESP_IMPLEMENTED;161 return 1;162 99 default: 163 100 fprintf( stderr, "subunit inquiry command 0x%02x not supported\n", cr->opcode ); … … 183 120 int unit_status( avc1394_cmd_rsp *cr ) 184 121 { 185 cr->operand[1] = 0x ff;186 cr->operand[2] = 0x ff;187 cr->operand[3] = 0x ff;188 cr->operand[4] = 0x ff;122 cr->operand[1] = 0x00; 123 cr->operand[2] = 0x00; 124 cr->operand[3] = 0x00; 125 cr->operand[4] = 0x00; 189 126 switch ( cr->opcode ) 190 127 { … … 192 129 cr->status = AVC1394_RESP_STABLE; 193 130 cr->operand[0] = AVC1394_OPERAND_UNIT_INFO_EXTENSION_CODE; 194 cr->operand[1] = AVC1394_SUBUNIT_TYPE_ TAPE_RECORDER >> 19;131 cr->operand[1] = AVC1394_SUBUNIT_TYPE_FREEBOB_BOUNCE_SERVER >> 19; 195 132 break; 196 133 case AVC1394_CMD_SUBUNIT_INFO: … … 201 138 cr->status = AVC1394_RESP_STABLE; 202 139 cr->operand[0] = (page << 4) | AVC1394_OPERAND_UNIT_INFO_EXTENSION_CODE; 203 cr->operand[1] = AVC1394_SUBUNIT_TYPE_ TAPE_RECORDER >> 19 << 3;140 cr->operand[1] = AVC1394_SUBUNIT_TYPE_FREEBOB_BOUNCE_SERVER >> 19 << 3; 204 141 } 205 142 … … 239 176 switch ( cr->subunit_type ) 240 177 { 241 case AVC1394_SUBUNIT_T APE_RECORDER:178 case AVC1394_SUBUNIT_TYPE_FREEBOB_BOUNCE_SERVER: 242 179 if ( cr->subunit_id != 0 ) 243 180 { … … 353 290 /* change the vendor description for kicks */ 354 291 i = strlen(dir.textual_leafs[0]); 355 strncpy(dir.textual_leafs[0], "FreeBob Server", i);292 strncpy(dir.textual_leafs[0], FREEBOB_BOUNCE_SERVER_VENDORNAME " ", i); 356 293 retval = rom1394_set_directory(rom, &dir); 357 294 printf("rom1394_set_directory returned %d, romsize %d:",retval,rom_size); … … 369 306 dir.unit_spec_id = 0x0000a02d; 370 307 dir.unit_sw_version = 0x00010001; 371 leaf = "freebob-server";308 leaf = FREEBOB_BOUNCE_SERVER_MODELNAME; 372 309 dir.nr_textual_leafs = 1; 373 310 dir.textual_leafs = &leaf; branches/libfreebob-2.0/tests/test-freebob.c
r185 r199 22 22 23 23 #include "libfreebob/freebob.h" 24 #include "libfreebob/freebob_bounce.h" 24 25 25 26 #include <argp.h>