/* * Copyright (C) 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 "AMBE3000Thread.h" #include "DStarDefines.h" const unsigned int MAX_PACKETS = 10U; CAMBE3000Thread::CAMBE3000Thread(CDV3000Controller* dongle) : CDongleThread(), m_dongle(dongle), m_wantMode(A3_IDLE), m_mode(A3_IDLE), m_packets(0U) { wxASSERT(dongle != NULL); } CAMBE3000Thread::~CAMBE3000Thread() { } bool CAMBE3000Thread::open() { m_mode = m_wantMode = A3_IDLE; m_packets = 0U; return m_dongle->open(); } void* CAMBE3000Thread::Entry() { while (!m_killed) { if (m_mode != m_wantMode) { if (m_mode == A3_DECODE && m_packets == 0U && m_decodeData.isEmpty()) { if (m_bleep) sendBleep(); reset(); m_mode = m_wantMode; } else if (m_mode == A3_ENCODE && m_packets == 0U && m_encodeAudio.isEmpty()) { reset(); m_mode = m_wantMode; } else if (m_mode == A3_IDLE) { m_mode = m_wantMode; } } switch (m_mode) { case A3_DECODE: processDecodeIn(); processDecodeOut(); break; case A3_ENCODE: processEncodeIn(); processEncodeOut(); break; default: break; } Sleep(5UL); } m_dongle->close(); delete m_dongle; return NULL; } void CAMBE3000Thread::setDecode() { if (m_mode != A3_DECODE && m_decodeCallback == NULL) return; m_wantMode = A3_DECODE; } void CAMBE3000Thread::setEncode() { if (m_mode != A3_ENCODE && m_encodeCallback == NULL) return; m_wantMode = A3_ENCODE; } void CAMBE3000Thread::setIdle() { m_wantMode = A3_IDLE; } void CAMBE3000Thread::processDecodeIn() { if (m_packets >= MAX_PACKETS) return; unsigned char ambe[VOICE_FRAME_LENGTH_BYTES]; unsigned int len = m_decodeData.getData(ambe, VOICE_FRAME_LENGTH_BYTES); if (len == 0U) return; // Convert the AMBE data to real audio, even if it's nonsense m_dongle->decodeIn(ambe, VOICE_FRAME_LENGTH_BYTES); m_packets++; } void CAMBE3000Thread::processDecodeOut() { wxFloat32 audioIn[DSTAR_AUDIO_BLOCK_SIZE]; bool res = m_dongle->decodeOut(audioIn, DSTAR_AUDIO_BLOCK_SIZE); if (res) { wxFloat32 audioOut[DSTAR_RADIO_BLOCK_SIZE]; upSample(audioIn, audioOut); m_decodeCallback->decodeCallback(audioOut, DSTAR_RADIO_BLOCK_SIZE); if (m_packets > 0U) m_packets--; } } void CAMBE3000Thread::processEncodeIn() { if (m_packets >= MAX_PACKETS) return; wxFloat32 audioIn[DSTAR_RADIO_BLOCK_SIZE]; ::memset(audioIn, 0x00, DSTAR_RADIO_BLOCK_SIZE * sizeof(wxFloat32)); unsigned int len = m_encodeAudio.getData(audioIn, DSTAR_RADIO_BLOCK_SIZE); if (len == 0U) return; wxFloat32 audioOut[DSTAR_AUDIO_BLOCK_SIZE]; downSample(audioIn, audioOut); // Convert the audio into AMBE data m_dongle->encodeIn(audioOut, DSTAR_AUDIO_BLOCK_SIZE); m_packets++; } void CAMBE3000Thread::processEncodeOut() { unsigned char ambe[VOICE_FRAME_LENGTH_BYTES]; bool res = m_dongle->encodeOut(ambe, VOICE_FRAME_LENGTH_BYTES); if (res) { m_encodeCallback->encodeCallback(ambe, VOICE_FRAME_LENGTH_BYTES); if (m_packets > 0U) m_packets--; } }