/*
 *   Copyright (C) 2010,2011,2012,2014 by Jonathan Naylor G4KLX
 *
 *   This program 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.
 *
 *   This program 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 this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "DVDongleThread.h"
#include "DStarDefines.h"

CDVDongleThread::CDVDongleThread(CDVDongleController* dongle) :
CDongleThread(),
m_dongle(dongle),
m_wantMode(DM_IDLE),
m_mode(DM_IDLE)
{
	wxASSERT(dongle != NULL);
}

CDVDongleThread::~CDVDongleThread()
{
}

bool CDVDongleThread::open()
{
	return m_dongle->open();
}

void* CDVDongleThread::Entry()
{
	m_dongle->start();

	while (!m_killed) {
		if (m_mode != m_wantMode) {
			if (m_mode == DM_DECODE && m_bleep)
				sendBleep();

			// Reset the FIR filter shift register
			reset();

			m_mode = m_wantMode;
		}

		switch (m_mode) {
			case DM_IDLE:
				processIdle();
				break;

			case DM_DECODE:
				processDecode();
				break;

			case DM_ENCODE:
				processEncode();
				break;
		}
	}

	m_dongle->stop();
	m_dongle->close();
	delete m_dongle;

	return NULL;
}

void CDVDongleThread::setDecode()
{
	if (m_mode == DM_ENCODE && m_decodeCallback == NULL)
		return;

	m_wantMode = DM_DECODE;
}

void CDVDongleThread::setEncode()
{
	if (m_mode == DM_DECODE && m_encodeCallback == NULL)
		return;

	m_wantMode = DM_ENCODE;
}

void CDVDongleThread::setIdle()
{
	m_wantMode = DM_IDLE;
}

void CDVDongleThread::processDecode()
{
	unsigned char ambe[VOICE_FRAME_LENGTH_BYTES];
	::memset(ambe, 0x00, VOICE_FRAME_LENGTH_BYTES);

	m_decodeData.getData(ambe, VOICE_FRAME_LENGTH_BYTES);

	// Convert the AMBE data to real audio, even if it's nonsense
	m_dongle->decodeIn(ambe, VOICE_FRAME_LENGTH_BYTES);

	wxFloat32 audioIn[DSTAR_AUDIO_BLOCK_SIZE];
	bool res = m_dongle->decodeOut(audioIn, DSTAR_AUDIO_BLOCK_SIZE);
	if (!res)
		wxLogError(wxT("An error occurred in decodeOut"));

	wxFloat32 audioOut[DSTAR_RADIO_BLOCK_SIZE];
	upSample(audioIn, audioOut);

	m_decodeCallback->decodeCallback(audioOut, DSTAR_RADIO_BLOCK_SIZE);
}

void CDVDongleThread::processEncode()
{
	wxFloat32 audioIn[DSTAR_RADIO_BLOCK_SIZE];
	::memset(audioIn, 0x00, DSTAR_RADIO_BLOCK_SIZE * sizeof(wxFloat32));

	m_encodeAudio.getData(audioIn, DSTAR_RADIO_BLOCK_SIZE);

	wxFloat32 audioOut[DSTAR_AUDIO_BLOCK_SIZE];
	downSample(audioIn, audioOut);

	// Convert the audio into AMBE data
	m_dongle->encodeIn(audioOut, DSTAR_AUDIO_BLOCK_SIZE);

	unsigned char ambe[VOICE_FRAME_LENGTH_BYTES];
	bool res = m_dongle->encodeOut(ambe, VOICE_FRAME_LENGTH_BYTES);
	if (!res)
		wxLogError(wxT("An error occurred in encodeOut"));

	m_encodeCallback->encodeCallback(ambe, VOICE_FRAME_LENGTH_BYTES);
}

void CDVDongleThread::processIdle()
{
	unsigned char ambe[VOICE_FRAME_LENGTH_BYTES];
	::memset(ambe, 0x00, VOICE_FRAME_LENGTH_BYTES);

	// Convert the AMBE data to real audio, even if it's nonsense
	m_dongle->decodeIn(ambe, VOICE_FRAME_LENGTH_BYTES);

	wxFloat32 audio[DSTAR_RADIO_BLOCK_SIZE];
	bool res = m_dongle->decodeOut(audio, DSTAR_AUDIO_BLOCK_SIZE);
	if (!res)
		wxLogError(wxT("An error occurred in decodeOut"));
}
