/* -*- c++ -*- */
/*
 * Copyright 2004 Free Software Foundation, Inc.
 * 
 * This file is part of GNU Radio
 * 
 * GNU Radio 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, or (at your option)
 * any later version.
 * 
 * GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */

static const int phase_table[4] = {+1, +3, -1, -3};

/*
 * config.h is generated by configure.  It contains the results
 * of probing for features, options etc.  It should be the first
 * file included in your .cc file.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gr_io_signature.h>
#include <gr_prefs.h>
#include <gr_math.h>
#include <gr_expj.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <repeater_chan_usrp_rx.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>

#ifndef min
#define min(a,b) ((a<b)?a:b)
#endif

/*
 * Create a new instance of repeater_chan_usrp_rx and return
 * a boost shared_ptr.  This is effectively the public constructor.
 */
repeater_chan_usrp_rx_sptr 
repeater_make_chan_usrp_rx (const char* udp_host, int port, int debug)
{
  return repeater_chan_usrp_rx_sptr (new repeater_chan_usrp_rx(udp_host, port, debug));
}

/*
 * The private constructor
 */
repeater_chan_usrp_rx::repeater_chan_usrp_rx (const char* udp_host, int port, int debug)
  : gr_block ("chan_usrp_rx",
		   gr_make_io_signature (1, 1, sizeof(short)),
		   gr_make_io_signature (0, 0, 0)),
	d_udp_host(udp_host),
	d_port(port),
	d_debug(debug),
	d_sampbuf_ct(0),
	d_sendseq(0)
{
	init_sock(udp_host, port);
}

repeater_chan_usrp_rx::~repeater_chan_usrp_rx ()
{
	if (write_sock > 0)
		close(write_sock);
}

static int sends, samps;

int 
repeater_chan_usrp_rx::general_work (int noutput_items,
                               gr_vector_int &ninput_items,
                               gr_vector_const_void_star &input_items,
                               gr_vector_void_star &output_items)
{
	struct timeval tv;
	const int16_t *in = (const int16_t *) input_items[0];
	int16_t *sampbuf = (int16_t *) &write_buf[sizeof(struct _chan_usrp_bufhdr)];
	struct _chan_usrp_bufhdr *bufhdrp = (struct _chan_usrp_bufhdr*) write_buf;
	gettimeofday(&tv, NULL);
//	fprintf(stderr, "sec %lu usec %lu output %d\n", tv.tv_sec, tv.tv_usec, noutput_items);

	int consumed = 0;

	for (int i = 0; i < noutput_items; i++) {
		int16_t samp = in[i];
		sampbuf[d_sampbuf_ct++] = samp;
		consumed++;
		if (d_sampbuf_ct >= (USRP_VOICE_FRAME_SIZE>>1)) {
			d_sampbuf_ct = 0;
			memset(bufhdrp, 0, sizeof(struct _chan_usrp_bufhdr));
			memcpy(bufhdrp->eye, "USRP", 4);
			bufhdrp->seq = htonl(d_sendseq++);
			bufhdrp->keyup = htonl(1);
			int rc = sendto(write_sock, write_buf, sizeof(struct _chan_usrp_bufhdr) + USRP_VOICE_FRAME_SIZE, 0, (struct sockaddr *)&write_sock_addr, sizeof(write_sock_addr));
//			gettimeofday(&tv, NULL);
//			fprintf(stderr, "rc %d sends %d samps %u sec %lu usec %lu\n", rc, sends++, samps, tv.tv_sec, tv.tv_usec);
			break;
		}
	}
	consume_each(consumed);
	return 0;
}

void repeater_chan_usrp_rx::unkey(void)
{
	struct _chan_usrp_bufhdr bufhdr;
	memset(&bufhdr, 0, sizeof(struct _chan_usrp_bufhdr));
	memcpy(bufhdr.eye, "USRP", 4);
	bufhdr.seq = htonl(d_sendseq++);	// FIXME: need to lock this?
	sendto(write_sock, &bufhdr, sizeof(struct _chan_usrp_bufhdr), 0, (struct sockaddr *)&write_sock_addr, sizeof(write_sock_addr));
}

void repeater_chan_usrp_rx::init_sock(const char* udp_host, int udp_port)
{
        memset (&write_sock_addr, 0, sizeof(write_sock_addr));
        write_sock = socket(PF_INET, SOCK_DGRAM, 17);   // UDP socket
        if (write_sock < 0) {
                fprintf(stderr, "op25_imbe_vocoder: socket: %d\n", errno);
                write_sock = 0;
		return;
        }
        if (!inet_aton(udp_host, &write_sock_addr.sin_addr)) {
                fprintf(stderr, "op25_imbe_vocoder: inet_aton: bad IP address\n");
		close(write_sock);
		write_sock = 0;
		return;
	}
        write_sock_addr.sin_family = AF_INET;
        write_sock_addr.sin_port = htons(udp_port);
}
