|
Packit |
0bbbb1 |
/*
|
|
Packit |
0bbbb1 |
* libiec61883 - Linux IEEE 1394 streaming media library.
|
|
Packit |
0bbbb1 |
* Copyright (C) 2004 Kristian Hogsberg, Dan Dennedy, and Dan Maas.
|
|
Packit |
0bbbb1 |
* This file written by Kristian Hogsberg.
|
|
Packit |
0bbbb1 |
*
|
|
Packit |
0bbbb1 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
0bbbb1 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
0bbbb1 |
* License as published by the Free Software Foundation; either
|
|
Packit |
0bbbb1 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
0bbbb1 |
*
|
|
Packit |
0bbbb1 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
0bbbb1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
0bbbb1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
0bbbb1 |
* Lesser General Public License for more details.
|
|
Packit |
0bbbb1 |
*
|
|
Packit |
0bbbb1 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
0bbbb1 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
0bbbb1 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
0bbbb1 |
*/
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
0bbbb1 |
#include <config.h>
|
|
Packit |
0bbbb1 |
#endif
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
#include "iec61883.h"
|
|
Packit |
0bbbb1 |
#include "iec61883-private.h"
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
#include <netinet/in.h>
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
/* Integer fractional math. When we transmit a 44k1Hz signal we must
|
|
Packit |
0bbbb1 |
* send 5 41/80 samples per isochronous cycle, as these occur 8000
|
|
Packit |
0bbbb1 |
* times a second. Of course, we must send an integral number of
|
|
Packit |
0bbbb1 |
* samples in a packet, so we use the integer math to alternate
|
|
Packit |
0bbbb1 |
* between sending 5 and 6 samples per packet.
|
|
Packit |
0bbbb1 |
*/
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
static void
|
|
Packit |
0bbbb1 |
fraction_init(struct iec61883_fraction *f, int numerator, int denominator)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
f->integer = numerator / denominator;
|
|
Packit |
0bbbb1 |
f->numerator = numerator % denominator;
|
|
Packit |
0bbbb1 |
f->denominator = denominator;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
static __inline__ void
|
|
Packit |
0bbbb1 |
fraction_add(struct iec61883_fraction *dst,
|
|
Packit |
0bbbb1 |
struct iec61883_fraction *src1, struct iec61883_fraction *src2)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
/* assert: src1->denominator == src2->denominator */
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
int sum, denom;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
/* We use these two local variables to allow gcc to optimize
|
|
Packit |
0bbbb1 |
* the division and the modulo into only one division. */
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
sum = src1->numerator + src2->numerator;
|
|
Packit |
0bbbb1 |
denom = src1->denominator;
|
|
Packit |
0bbbb1 |
dst->integer = src1->integer + src2->integer + sum / denom;
|
|
Packit |
0bbbb1 |
dst->numerator = sum % denom;
|
|
Packit |
0bbbb1 |
dst->denominator = denom;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
static __inline__ void
|
|
Packit |
0bbbb1 |
fraction_sub_int(struct iec61883_fraction *dst, struct iec61883_fraction *src, int integer)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
dst->integer = src->integer - integer;
|
|
Packit |
0bbbb1 |
dst->numerator = src->numerator;
|
|
Packit |
0bbbb1 |
dst->denominator = src->denominator;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
static __inline__ int
|
|
Packit |
0bbbb1 |
fraction_floor(struct iec61883_fraction *frac)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
return frac->integer;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
static __inline__ int
|
|
Packit |
0bbbb1 |
fraction_ceil(struct iec61883_fraction *frac)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
return frac->integer + (frac->numerator > 0 ? 1 : 0);
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
void
|
|
Packit |
0bbbb1 |
iec61883_cip_init(struct iec61883_cip *ptz, int format, int fdf,
|
|
Packit |
0bbbb1 |
int rate, int dbs, int syt_interval)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
const int transfer_delay = 9000;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
ptz->rate = rate;
|
|
Packit |
0bbbb1 |
ptz->cycle_count = transfer_delay / 3072;
|
|
Packit |
0bbbb1 |
ptz->format = format;
|
|
Packit |
0bbbb1 |
ptz->fdf = fdf;
|
|
Packit |
0bbbb1 |
ptz->mode = IEC61883_MODE_BLOCKING_EMPTY;
|
|
Packit |
0bbbb1 |
ptz->dbs = dbs;
|
|
Packit |
0bbbb1 |
ptz->dbc = 0;
|
|
Packit |
0bbbb1 |
ptz->syt_interval = syt_interval;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
fraction_init(&ptz->samples_per_cycle, ptz->rate, 8000);
|
|
Packit |
0bbbb1 |
fraction_init(&ptz->ready_samples, 0, 8000);
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
/* The ticks_per_syt_offset is initialized to the number of
|
|
Packit |
0bbbb1 |
* ticks between syt_interval events. The number of ticks per
|
|
Packit |
0bbbb1 |
* second is 24.576e6, so the number of ticks between
|
|
Packit |
0bbbb1 |
* syt_interval events is 24.576e6 * syt_interval / rate.
|
|
Packit |
0bbbb1 |
*/
|
|
Packit |
0bbbb1 |
fraction_init(&ptz->ticks_per_syt_offset,
|
|
Packit |
0bbbb1 |
24576000 * ptz->syt_interval, ptz->rate);
|
|
Packit |
0bbbb1 |
fraction_init(&ptz->cycle_offset,
|
|
Packit |
0bbbb1 |
(transfer_delay % 3072) * ptz->rate, ptz->rate);
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
void
|
|
Packit |
0bbbb1 |
iec61883_cip_resync(struct iec61883_cip *ptz, int cycle)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
const int transfer_delay = 9000;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
ptz->cycle_count = cycle + (transfer_delay / 3072);
|
|
Packit |
0bbbb1 |
fraction_init(&ptz->cycle_offset,
|
|
Packit |
0bbbb1 |
(transfer_delay % 3072) * ptz->rate, ptz->rate);
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
fraction_init(&ptz->ready_samples, 0, 8000);
|
|
Packit |
0bbbb1 |
ptz->dbc = 0;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
void
|
|
Packit |
0bbbb1 |
iec61883_cip_set_transmission_mode(struct iec61883_cip *ptz, int mode)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
ptz->mode = mode;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
int
|
|
Packit |
0bbbb1 |
iec61883_cip_get_max_packet_size(struct iec61883_cip *ptz)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
int max_nevents;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
if (ptz->mode == IEC61883_MODE_BLOCKING_EMPTY || ptz->mode == IEC61883_MODE_BLOCKING_NODATA)
|
|
Packit |
0bbbb1 |
max_nevents = ptz->syt_interval;
|
|
Packit |
0bbbb1 |
else
|
|
Packit |
0bbbb1 |
max_nevents = fraction_ceil(&ptz->samples_per_cycle);
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
return max_nevents * ptz->dbs * 4 + 8;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
int
|
|
Packit |
0bbbb1 |
iec61883_cip_fill_header(raw1394handle_t handle, struct iec61883_cip *ptz,
|
|
Packit |
0bbbb1 |
struct iec61883_packet *packet)
|
|
Packit |
0bbbb1 |
{
|
|
Packit |
0bbbb1 |
struct iec61883_fraction next;
|
|
Packit |
0bbbb1 |
int nevents, nevents_dbc, syt_index, syt;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
fraction_add(&next, &ptz->ready_samples, &ptz->samples_per_cycle);
|
|
Packit |
0bbbb1 |
if (ptz->mode == IEC61883_MODE_BLOCKING_EMPTY ||
|
|
Packit |
0bbbb1 |
ptz->mode == IEC61883_MODE_BLOCKING_NODATA) {
|
|
Packit |
0bbbb1 |
if (fraction_floor(&next) >= ptz->syt_interval)
|
|
Packit |
0bbbb1 |
nevents = ptz->syt_interval;
|
|
Packit |
0bbbb1 |
else
|
|
Packit |
0bbbb1 |
nevents = 0;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
else
|
|
Packit |
0bbbb1 |
nevents = fraction_floor(&next;;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
if (ptz->mode == IEC61883_MODE_BLOCKING_NODATA) {
|
|
Packit |
0bbbb1 |
/* The DBC is incremented even with NO_DATA packets. */
|
|
Packit |
0bbbb1 |
nevents_dbc = ptz->syt_interval;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
else {
|
|
Packit |
0bbbb1 |
nevents_dbc = nevents;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
/* Now that we know how many events to put in the packet, update the
|
|
Packit |
0bbbb1 |
* fraction ready_samples. */
|
|
Packit |
0bbbb1 |
fraction_sub_int(&ptz->ready_samples, &next, nevents);
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
/* Calculate synchronization timestamp (syt). First we
|
|
Packit |
0bbbb1 |
* determine syt_index, that is, the index in the packet of
|
|
Packit |
0bbbb1 |
* the sample for which the timestamp is valid. */
|
|
Packit |
0bbbb1 |
syt_index = (ptz->syt_interval - ptz->dbc) & (ptz->syt_interval - 1);
|
|
Packit |
0bbbb1 |
if (syt_index < nevents) {
|
|
Packit |
0bbbb1 |
syt = ((ptz->cycle_count << 12) | fraction_floor(&ptz->cycle_offset)) & 0xffff;
|
|
Packit |
0bbbb1 |
fraction_add(&ptz->cycle_offset, &ptz->cycle_offset,
|
|
Packit |
0bbbb1 |
&ptz->ticks_per_syt_offset);
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
/* The cycle_count field is a 13 bits value that goes from 0 to 7999.
|
|
Packit |
0bbbb1 |
* The cycle_offset field is a 12 bits value that goes from 0 to 3071. */
|
|
Packit |
0bbbb1 |
ptz->cycle_count += ptz->cycle_offset.integer / 3072;
|
|
Packit |
0bbbb1 |
ptz->cycle_count %= 8000;
|
|
Packit |
0bbbb1 |
ptz->cycle_offset.integer %= 3072;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
else
|
|
Packit |
0bbbb1 |
syt = 0xffff;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
packet->eoh0 = 0;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
/* Our node ID can change after a bus reset, so it is best to fetch
|
|
Packit |
0bbbb1 |
* our node ID for each packet. */
|
|
Packit |
0bbbb1 |
packet->sid = raw1394_get_local_id( handle ) & 0x3f;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
packet->dbs = ptz->dbs;
|
|
Packit |
0bbbb1 |
packet->fn = 0;
|
|
Packit |
0bbbb1 |
packet->qpc = 0;
|
|
Packit |
0bbbb1 |
packet->sph = 0;
|
|
Packit |
0bbbb1 |
packet->reserved = 0;
|
|
Packit |
0bbbb1 |
packet->dbc = ptz->dbc;
|
|
Packit |
0bbbb1 |
packet->eoh1 = 2;
|
|
Packit |
0bbbb1 |
packet->fmt = ptz->format;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
if ( nevents == 0 && ptz->mode == IEC61883_MODE_BLOCKING_NODATA ) {
|
|
Packit |
0bbbb1 |
/* FDF code for packets containing dummy data. */
|
|
Packit |
0bbbb1 |
packet->fdf = IEC61883_FDF_NODATA;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
else {
|
|
Packit |
0bbbb1 |
/* FDF code for non-blocking mode and for blocking mode with empty packets. */
|
|
Packit |
0bbbb1 |
packet->fdf = ptz->fdf;
|
|
Packit |
0bbbb1 |
}
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
packet->syt = htons(syt);
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
ptz->dbc += nevents_dbc;
|
|
Packit |
0bbbb1 |
|
|
Packit |
0bbbb1 |
return nevents;
|
|
Packit |
0bbbb1 |
}
|