Create rig control interface and port Hamlib implementation to it.
parent
5ddbdf0563
commit
55872ce43d
|
@ -44,3 +44,4 @@ list(APPEND FREEDV_STATIC_DEPS hamlib)
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector")
|
||||||
|
set(HAMLIB_ADD_DEPENDENCY TRUE)
|
|
@ -55,7 +55,9 @@ add_subdirectory(config)
|
||||||
add_subdirectory(gui)
|
add_subdirectory(gui)
|
||||||
add_subdirectory(pipeline)
|
add_subdirectory(pipeline)
|
||||||
add_subdirectory(reporting)
|
add_subdirectory(reporting)
|
||||||
|
add_subdirectory(rig_control)
|
||||||
add_subdirectory(sox)
|
add_subdirectory(sox)
|
||||||
|
add_subdirectory(util)
|
||||||
|
|
||||||
# WIN32 is needed for Windows GUI apps and is ignored for UNIX like systems.
|
# WIN32 is needed for Windows GUI apps and is ignored for UNIX like systems.
|
||||||
# In addition, there are some required OSX-specific code files for platform specific handling.
|
# In addition, there are some required OSX-specific code files for platform specific handling.
|
||||||
|
@ -80,9 +82,9 @@ endif(APPLE)
|
||||||
|
|
||||||
# Link imported or build tree targets.
|
# Link imported or build tree targets.
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(FreeDV fdv_audio fdv_audio_pipeline fdv_config fdv_gui_util fdv_reporting fdv_sox lpcnetfreedv codec2)
|
target_link_libraries(FreeDV fdv_audio fdv_audio_pipeline fdv_config fdv_gui_util fdv_reporting fdv_rig_control fdv_sox fdv_util lpcnetfreedv codec2)
|
||||||
else(APPLE)
|
else(APPLE)
|
||||||
target_link_libraries(freedv fdv_audio fdv_audio_pipeline fdv_config fdv_gui_util fdv_reporting fdv_sox lpcnetfreedv codec2)
|
target_link_libraries(freedv fdv_audio fdv_audio_pipeline fdv_config fdv_gui_util fdv_reporting fdv_rig_control fdv_sox fdv_util lpcnetfreedv codec2)
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
# Add build dependencies for internally built external libraries.
|
# Add build dependencies for internally built external libraries.
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
add_library(fdv_rig_control STATIC
|
||||||
|
HamlibRigController.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(fdv_rig_control PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..)
|
||||||
|
|
||||||
|
if(HAMLIB_ADD_DEPENDENCY)
|
||||||
|
add_dependencies(fdv_rig_control hamlib)
|
||||||
|
endif(HAMLIB_ADD_DEPENDENCY)
|
|
@ -0,0 +1,563 @@
|
||||||
|
//=========================================================================
|
||||||
|
// Name: HamlibRigController.cpp
|
||||||
|
// Purpose: Controls radios using Hamlib library.
|
||||||
|
//
|
||||||
|
// Authors: Mooneer Salem
|
||||||
|
// License:
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2.1,
|
||||||
|
// as published by the Free Software Foundation. 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "HamlibRigController.h"
|
||||||
|
|
||||||
|
extern int g_verbose;
|
||||||
|
|
||||||
|
HamlibRigController::RigList HamlibRigController::RigList_;
|
||||||
|
std::mutex HamlibRigController::RigListMutex_;
|
||||||
|
|
||||||
|
int HamlibRigController::BuildRigList_(const struct rig_caps *rig, rig_ptr_t rigList) {
|
||||||
|
((HamlibRigController::RigList *)rigList)->push_back(rig);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HamlibRigController::RigCompare_(const struct rig_caps *rig1, const struct rig_caps *rig2) {
|
||||||
|
/* Compare manufacturer. */
|
||||||
|
int r = strcasecmp(rig1->mfg_name, rig2->mfg_name);
|
||||||
|
if (r != 0)
|
||||||
|
return r < 0;
|
||||||
|
|
||||||
|
/* Compare model. */
|
||||||
|
r = strcasecmp(rig1->model_name, rig2->model_name);
|
||||||
|
if (r != 0)
|
||||||
|
return r < 0;
|
||||||
|
|
||||||
|
/* Compare rig ID. */
|
||||||
|
return rig1->rig_model < rig2->rig_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
HamlibRigController::HamlibRigController(std::string rigName, std::string serialPort, const int serialRate, const int civHex, const PttType pttType, std::string pttSerialPort)
|
||||||
|
: rigName_(rigName)
|
||||||
|
, serialPort_(serialPort)
|
||||||
|
, serialRate_(serialRate)
|
||||||
|
, civHex_(civHex)
|
||||||
|
, pttType_(pttType)
|
||||||
|
, pttSerialPort_(pttSerialPort)
|
||||||
|
, rig_(nullptr)
|
||||||
|
, multipleVfos_(false)
|
||||||
|
, pttSet_(false)
|
||||||
|
{
|
||||||
|
// Perform initial load of rig list if this is our first time being created.
|
||||||
|
std::unique_lock<std::mutex> lk(RigListMutex_);
|
||||||
|
if (RigList_.size() == 0)
|
||||||
|
{
|
||||||
|
/* Stop hamlib from spewing info to stderr. */
|
||||||
|
rig_set_debug(RIG_DEBUG_NONE);
|
||||||
|
|
||||||
|
/* Create sorted list of rigs. */
|
||||||
|
rig_load_all_backends();
|
||||||
|
rig_list_foreach(&HamlibRigController::BuildRigList_, &RigList_);
|
||||||
|
sort(RigList_.begin(), RigList_.end(), &HamlibRigController::RigCompare_);
|
||||||
|
|
||||||
|
/* Reset debug output. */
|
||||||
|
rig_set_debug(RIG_DEBUG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HamlibRigController::~HamlibRigController()
|
||||||
|
{
|
||||||
|
// Disconnect in a synchronous fashion before killing our thread.
|
||||||
|
std::condition_variable cv;
|
||||||
|
std::mutex mtx;
|
||||||
|
std::unique_lock<std::mutex> lk(mtx);
|
||||||
|
|
||||||
|
enqueue_([&]() {
|
||||||
|
std::unique_lock<std::mutex> innerLock(mtx);
|
||||||
|
if (rig_ != nullptr)
|
||||||
|
{
|
||||||
|
disconnectImpl_();
|
||||||
|
}
|
||||||
|
cv.notify_one();
|
||||||
|
});
|
||||||
|
|
||||||
|
cv.wait(lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::connect()
|
||||||
|
{
|
||||||
|
enqueue_(std::bind(&HamlibRigController::connectImpl_, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::disconnect()
|
||||||
|
{
|
||||||
|
enqueue_(std::bind(&HamlibRigController::disconnectImpl_, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::ptt(bool state)
|
||||||
|
{
|
||||||
|
enqueue_(std::bind(&HamlibRigController::pttImpl_, this, state));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::setFrequency(uint64_t frequency)
|
||||||
|
{
|
||||||
|
enqueue_(std::bind(&HamlibRigController::setFrequencyImpl_, this, frequency));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::setMode(IRigFrequencyController::Mode mode)
|
||||||
|
{
|
||||||
|
enqueue_(std::bind(&HamlibRigController::setModeImpl_, this, mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::requestCurrentFrequencyMode()
|
||||||
|
{
|
||||||
|
enqueue_(std::bind(&HamlibRigController::requestCurrentFrequencyModeImpl_, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int HamlibRigController::rigNameToIndex_(std::string rigName)
|
||||||
|
{
|
||||||
|
unsigned int index = 0;
|
||||||
|
for (auto& entry : RigList_)
|
||||||
|
{
|
||||||
|
char name[128];
|
||||||
|
snprintf(name, 128, "%s %s", entry->mfg_name, entry->model_name);
|
||||||
|
|
||||||
|
if (rigName == std::string(name))
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: these execute in the thread created by ThreadedObject on object instantiation.
|
||||||
|
|
||||||
|
void HamlibRigController::connectImpl_()
|
||||||
|
{
|
||||||
|
if (rig_ != nullptr)
|
||||||
|
{
|
||||||
|
std::string errMsg = "Already connected to radio.";
|
||||||
|
onRigError(this, errMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rigIndex = rigNameToIndex_(rigName_);
|
||||||
|
if (rigIndex == -1)
|
||||||
|
{
|
||||||
|
std::string errMsg = "Could not find rig " + rigName_ + " in Hamlib database.";
|
||||||
|
onRigError(this, errMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise, configure and open. */
|
||||||
|
rig_ = rig_init(RigList_[rigIndex]->rig_model);
|
||||||
|
if (!rig_)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_init() failed, returning\n");
|
||||||
|
|
||||||
|
std::string errMsg = "Hamlib could not initialize rig " + rigName_;
|
||||||
|
onRigError(this, errMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_init() OK ....\n");
|
||||||
|
|
||||||
|
/* Set CI-V address if necessary. */
|
||||||
|
if (!strncmp(RigList_[rigIndex]->mfg_name, "Icom", 4))
|
||||||
|
{
|
||||||
|
char civAddr[5];
|
||||||
|
snprintf(civAddr, 5, "0x%0X", civHex_);
|
||||||
|
if (g_verbose) fprintf(stderr, "hamlib: setting CI-V address to: %s\n", civAddr);
|
||||||
|
rig_set_conf(rig_, rig_token_lookup(rig_, "civaddr"), civAddr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "hamlib: ignoring CI-V configuration due to non-Icom radio\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
rig_set_conf(rig_, rig_token_lookup(rig_, "rig_pathname"), serialPort_.c_str());
|
||||||
|
|
||||||
|
if (pttSerialPort_.size() > 0)
|
||||||
|
{
|
||||||
|
rig_set_conf(rig_, rig_token_lookup(rig_, "ptt_pathname"), pttSerialPort_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serialRate_ > 0)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "hamlib: setting serial rate: %d\n", serialRate_);
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << serialRate_;
|
||||||
|
rig_set_conf(rig_, rig_token_lookup(rig_, "serial_speed"), ss.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set PTT type as needed.
|
||||||
|
switch(pttType_)
|
||||||
|
{
|
||||||
|
case PTT_VIA_RTS:
|
||||||
|
rig_set_conf(rig_, rig_token_lookup(rig_, "ptt_type"), "RTS");
|
||||||
|
break;
|
||||||
|
case PTT_VIA_DTR:
|
||||||
|
rig_set_conf(rig_, rig_token_lookup(rig_, "ptt_type"), "DTR");
|
||||||
|
break;
|
||||||
|
case PTT_VIA_NONE:
|
||||||
|
rig_set_conf(rig_, rig_token_lookup(rig_, "ptt_type"), "NONE");
|
||||||
|
break;
|
||||||
|
case PTT_VIA_CAT:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rig_open(rig_) == RIG_OK)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "hamlib: rig_open() OK\n");
|
||||||
|
onRigConnected(this);
|
||||||
|
|
||||||
|
// Determine whether we have multiple VFOs.
|
||||||
|
multipleVfos_ = false;
|
||||||
|
vfo_t vfo;
|
||||||
|
if (rig_get_vfo (rig_, &vfo) == RIG_OK && (rig_->state.vfo_list & RIG_VFO_B))
|
||||||
|
{
|
||||||
|
multipleVfos_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current frequency and mode when we first connect so we can
|
||||||
|
// revert on close.
|
||||||
|
requestCurrentFrequencyMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (g_verbose) fprintf(stderr, "hamlib: rig_open() failed ...\n");
|
||||||
|
|
||||||
|
rig_cleanup(rig_);
|
||||||
|
rig_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::disconnectImpl_()
|
||||||
|
{
|
||||||
|
if (rig_)
|
||||||
|
{
|
||||||
|
// Stop transmitting.
|
||||||
|
if (pttSet_)
|
||||||
|
{
|
||||||
|
pttImpl_(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
rig_close(rig_);
|
||||||
|
rig_cleanup(rig_);
|
||||||
|
rig_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::pttImpl_(bool state)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr,"Hamlib::ptt: %d\n", state);
|
||||||
|
|
||||||
|
if (rig_ == nullptr)
|
||||||
|
{
|
||||||
|
onRigError(this, "Cannot set PTT: not connected to radio");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptt_t on = state ? RIG_PTT_ON : RIG_PTT_OFF;
|
||||||
|
|
||||||
|
int result = rig_set_ptt(rig_, RIG_VFO_CURR, on);
|
||||||
|
if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_set_ptt: error = %s \n", rigerror(result));
|
||||||
|
|
||||||
|
std::string errMsg = "Cannot set PTT: " + std::string(rigerror(result));
|
||||||
|
onRigError(this, errMsg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pttSet_ != state)
|
||||||
|
{
|
||||||
|
onPttChange(this, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
pttSet_ = state;
|
||||||
|
|
||||||
|
if (!state)
|
||||||
|
{
|
||||||
|
requestCurrentFrequencyMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::setFrequencyImpl_(uint64_t frequencyHz)
|
||||||
|
{
|
||||||
|
if (rig_ == nullptr)
|
||||||
|
{
|
||||||
|
onRigError(this, "Cannot get current frequency/mode: not connected to radio");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pttSet_)
|
||||||
|
{
|
||||||
|
// If transmitting, temporarily stop transmitting so we can change the mode.
|
||||||
|
int result = rig_set_ptt(rig_, RIG_VFO_CURR, RIG_PTT_OFF);
|
||||||
|
if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
// If we can't stop transmitting, we shouldn't try to change the mode
|
||||||
|
// as it'll fail on some radios.
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_set_ptt: error = %s \n", rigerror(result));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vfo_t currVfo = getCurrentVfo_();
|
||||||
|
setFrequencyHelper_(currVfo, frequencyHz);
|
||||||
|
|
||||||
|
if (pttSet_)
|
||||||
|
{
|
||||||
|
// If transmitting, temporarily stop transmitting so we can change the mode.
|
||||||
|
int result = rig_set_ptt(rig_, RIG_VFO_CURR, RIG_PTT_ON);
|
||||||
|
if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
// If we can't stop transmitting, we shouldn't try to change the mode
|
||||||
|
// as it'll fail on some radios.
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_set_ptt: error = %s \n", rigerror(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::setModeImpl_(IRigFrequencyController::Mode mode)
|
||||||
|
{
|
||||||
|
rmode_t hamlibMode;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case USB:
|
||||||
|
hamlibMode = RIG_MODE_USB;
|
||||||
|
break;
|
||||||
|
case LSB:
|
||||||
|
hamlibMode = RIG_MODE_LSB;
|
||||||
|
break;
|
||||||
|
case DIGU:
|
||||||
|
hamlibMode = RIG_MODE_PKTUSB;
|
||||||
|
break;
|
||||||
|
case DIGL:
|
||||||
|
hamlibMode = RIG_MODE_PKTLSB;
|
||||||
|
break;
|
||||||
|
case FM:
|
||||||
|
hamlibMode = RIG_MODE_FM;
|
||||||
|
break;
|
||||||
|
case DIGFM:
|
||||||
|
hamlibMode = RIG_MODE_PKTFM;
|
||||||
|
break;
|
||||||
|
case AM:
|
||||||
|
hamlibMode = RIG_MODE_AM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
onRigError(this, "Cannot set mode: mode not recognized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pttSet_)
|
||||||
|
{
|
||||||
|
// If transmitting, temporarily stop transmitting so we can change the mode.
|
||||||
|
int result = rig_set_ptt(rig_, RIG_VFO_CURR, RIG_PTT_OFF);
|
||||||
|
if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
// If we can't stop transmitting, we shouldn't try to change the mode
|
||||||
|
// as it'll fail on some radios.
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_set_ptt: error = %s \n", rigerror(result));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vfo_t currVfo = getCurrentVfo_();
|
||||||
|
setModeHelper_(currVfo, hamlibMode);
|
||||||
|
|
||||||
|
if (pttSet_)
|
||||||
|
{
|
||||||
|
// If transmitting, temporarily stop transmitting so we can change the mode.
|
||||||
|
int result = rig_set_ptt(rig_, RIG_VFO_CURR, RIG_PTT_ON);
|
||||||
|
if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
// If we can't stop transmitting, we shouldn't try to change the mode
|
||||||
|
// as it'll fail on some radios.
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_set_ptt: error = %s \n", rigerror(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::requestCurrentFrequencyModeImpl_()
|
||||||
|
{
|
||||||
|
if (rig_ == nullptr)
|
||||||
|
{
|
||||||
|
onRigError(this, "Cannot get current frequency/mode: not connected to radio");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rmode_t mode = RIG_MODE_NONE;
|
||||||
|
pbwidth_t passband = 0;
|
||||||
|
vfo_t currVfo = getCurrentVfo_();
|
||||||
|
|
||||||
|
modeAttempt:
|
||||||
|
int result = rig_get_mode(rig_, currVfo, &mode, &passband);
|
||||||
|
if (result != RIG_OK && currVfo == RIG_VFO_CURR)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_get_mode: error = %s \n", rigerror(result));
|
||||||
|
}
|
||||||
|
else if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
// We supposedly have multiple VFOs but ran into problems
|
||||||
|
// trying to get information about the supposed active VFO.
|
||||||
|
// Make a last ditch effort using RIG_VFO_CURR before fully failing.
|
||||||
|
currVfo = RIG_VFO_CURR;
|
||||||
|
goto modeAttempt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
freqAttempt:
|
||||||
|
freq_t freq = 0;
|
||||||
|
result = rig_get_freq(rig_, currVfo, &freq);
|
||||||
|
if (result != RIG_OK && currVfo == RIG_VFO_CURR)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_get_freq: error = %s \n", rigerror(result));
|
||||||
|
}
|
||||||
|
else if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
// We supposedly have multiple VFOs but ran into problems
|
||||||
|
// trying to get information about the supposed active VFO.
|
||||||
|
// Make a last ditch effort using RIG_VFO_CURR before fully failing.
|
||||||
|
currVfo = RIG_VFO_CURR;
|
||||||
|
goto freqAttempt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IRigFrequencyController::Mode currMode;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case RIG_MODE_USB:
|
||||||
|
currMode = USB;
|
||||||
|
break;
|
||||||
|
case RIG_MODE_LSB:
|
||||||
|
currMode = LSB;
|
||||||
|
break;
|
||||||
|
case RIG_MODE_PKTUSB:
|
||||||
|
currMode = DIGU;
|
||||||
|
break;
|
||||||
|
case RIG_MODE_PKTLSB:
|
||||||
|
currMode = DIGL;
|
||||||
|
break;
|
||||||
|
case RIG_MODE_FM:
|
||||||
|
currMode = FM;
|
||||||
|
break;
|
||||||
|
case RIG_MODE_PKTFM:
|
||||||
|
currMode = DIGFM;
|
||||||
|
break;
|
||||||
|
case RIG_MODE_AM:
|
||||||
|
currMode = AM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
currMode = UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFreqModeChange(this, freq, currMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vfo_t HamlibRigController::getCurrentVfo_()
|
||||||
|
{
|
||||||
|
vfo_t vfo = RIG_VFO_CURR;
|
||||||
|
|
||||||
|
if (multipleVfos_)
|
||||||
|
{
|
||||||
|
int result = rig_get_vfo(rig_, &vfo);
|
||||||
|
if (result != RIG_OK && result != -RIG_ENAVAIL)
|
||||||
|
{
|
||||||
|
// Note: we'll still attempt operation using RIG_VFO_CURR just in case.
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_get_vfo: error = %s \n", rigerror(result));
|
||||||
|
vfo = RIG_VFO_CURR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::setFrequencyHelper_(vfo_t currVfo, uint64_t frequencyHz)
|
||||||
|
{
|
||||||
|
bool setOkay = false;
|
||||||
|
|
||||||
|
freqAttempt:
|
||||||
|
int result = rig_set_freq(rig_, currVfo, frequencyHz);
|
||||||
|
if (result != RIG_OK && currVfo == RIG_VFO_CURR)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_set_freq: error = %s \n", rigerror(result));
|
||||||
|
}
|
||||||
|
else if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
// We supposedly have multiple VFOs but ran into problems
|
||||||
|
// trying to get information about the supposed active VFO.
|
||||||
|
// Make a last ditch effort using RIG_VFO_CURR before fully failing.
|
||||||
|
currVfo = RIG_VFO_CURR;
|
||||||
|
goto freqAttempt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setOkay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're able to set either frequency or mode, we should update the current state accordingly.
|
||||||
|
// The actual configuration of the radio (in case of failure) will auto-update within
|
||||||
|
// a few seconds after this update.
|
||||||
|
if (setOkay)
|
||||||
|
{
|
||||||
|
requestCurrentFrequencyMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HamlibRigController::setModeHelper_(vfo_t currVfo, rmode_t mode)
|
||||||
|
{
|
||||||
|
bool setOkay = false;
|
||||||
|
|
||||||
|
modeAttempt:
|
||||||
|
int result = rig_set_mode(rig_, currVfo, mode, RIG_PASSBAND_NOCHANGE);
|
||||||
|
if (result != RIG_OK && currVfo == RIG_VFO_CURR)
|
||||||
|
{
|
||||||
|
if (g_verbose) fprintf(stderr, "rig_set_mode: error = %s \n", rigerror(result));
|
||||||
|
}
|
||||||
|
else if (result != RIG_OK)
|
||||||
|
{
|
||||||
|
// We supposedly have multiple VFOs but ran into problems
|
||||||
|
// trying to get information about the supposed active VFO.
|
||||||
|
// Make a last ditch effort using RIG_VFO_CURR before fully failing.
|
||||||
|
currVfo = RIG_VFO_CURR;
|
||||||
|
goto modeAttempt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setOkay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're able to set either frequency or mode, we should update the current state accordingly.
|
||||||
|
// The actual configuration of the radio (in case of failure) will auto-update within
|
||||||
|
// a few seconds after this update.
|
||||||
|
if (setOkay)
|
||||||
|
{
|
||||||
|
requestCurrentFrequencyMode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
//=========================================================================
|
||||||
|
// Name: HamlibRigController.h
|
||||||
|
// Purpose: Controls radios using Hamlib library.
|
||||||
|
//
|
||||||
|
// Authors: Mooneer Salem
|
||||||
|
// License:
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2.1,
|
||||||
|
// as published by the Free Software Foundation. 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#ifndef HAMLIB_RIG_CONTROLLER_H
|
||||||
|
#define HAMLIB_RIG_CONTROLLER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "util/ThreadedObject.h"
|
||||||
|
#include "IRigFrequencyController.h"
|
||||||
|
#include "IRigPttController.h"
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <hamlib/rig.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
class HamlibRigController : public ThreadedObject, public IRigFrequencyController, public IRigPttController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum PttType
|
||||||
|
{
|
||||||
|
PTT_VIA_CAT = 0,
|
||||||
|
PTT_VIA_RTS,
|
||||||
|
PTT_VIA_DTR,
|
||||||
|
PTT_VIA_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
HamlibRigController(std::string rigName, std::string serialPort, const int serialRate, const int civHex = 0, const PttType pttType = PTT_VIA_CAT, std::string pttSerialPort = std::string());
|
||||||
|
virtual ~HamlibRigController();
|
||||||
|
|
||||||
|
virtual void connect() override;
|
||||||
|
virtual void disconnect() override;
|
||||||
|
virtual void ptt(bool state) override;
|
||||||
|
virtual void setFrequency(uint64_t frequency) override;
|
||||||
|
virtual void setMode(IRigFrequencyController::Mode mode) override;
|
||||||
|
virtual void requestCurrentFrequencyMode() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using RigList = std::vector<const struct rig_caps *>;
|
||||||
|
|
||||||
|
std::string rigName_;
|
||||||
|
std::string serialPort_;
|
||||||
|
const int serialRate_;
|
||||||
|
const int civHex_;
|
||||||
|
const PttType pttType_;
|
||||||
|
std::string pttSerialPort_;
|
||||||
|
|
||||||
|
RIG* rig_;
|
||||||
|
bool multipleVfos_;
|
||||||
|
bool pttSet_;
|
||||||
|
|
||||||
|
unsigned int rigNameToIndex_(std::string rigName);
|
||||||
|
vfo_t getCurrentVfo_();
|
||||||
|
void setFrequencyHelper_(vfo_t currVfo, uint64_t frequencyHz);
|
||||||
|
void setModeHelper_(vfo_t currVfo, rmode_t mode);
|
||||||
|
|
||||||
|
void connectImpl_();
|
||||||
|
void disconnectImpl_();
|
||||||
|
void pttImpl_(bool state);
|
||||||
|
void setFrequencyImpl_(uint64_t frequencyHz);
|
||||||
|
void setModeImpl_(IRigFrequencyController::Mode mode);
|
||||||
|
void requestCurrentFrequencyModeImpl_();
|
||||||
|
|
||||||
|
static RigList RigList_;
|
||||||
|
static std::mutex RigListMutex_;
|
||||||
|
|
||||||
|
static bool RigCompare_(const struct rig_caps *rig1, const struct rig_caps *rig2);
|
||||||
|
static int BuildRigList_(const struct rig_caps *rig, rig_ptr_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HAMLIB_RIG_CONTROLLER_H
|
|
@ -0,0 +1,46 @@
|
||||||
|
//=========================================================================
|
||||||
|
// Name: IRigController.h
|
||||||
|
// Purpose: Interface for control of radios.
|
||||||
|
//
|
||||||
|
// Authors: Mooneer Salem
|
||||||
|
// License:
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2.1,
|
||||||
|
// as published by the Free Software Foundation. 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#ifndef I_RIG_CONTROLLER_H
|
||||||
|
#define I_RIG_CONTROLLER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "util/EventHandler.h"
|
||||||
|
|
||||||
|
class IRigController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IRigController() = default;
|
||||||
|
|
||||||
|
// Event handlers common across all rig control objects.
|
||||||
|
EventHandler<IRigController*, std::string> onRigError;
|
||||||
|
EventHandler<IRigController*> onRigConnected;
|
||||||
|
EventHandler<IRigController*> onRigDisconnected;
|
||||||
|
|
||||||
|
virtual void connect() = 0;
|
||||||
|
virtual void disconnect() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IRigController() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // I_RIG_CONTROLLER_H
|
|
@ -0,0 +1,57 @@
|
||||||
|
//=========================================================================
|
||||||
|
// Name: IRigFrequencyController.h
|
||||||
|
// Purpose: Interface for control of frequency/mode on radios.
|
||||||
|
//
|
||||||
|
// Authors: Mooneer Salem
|
||||||
|
// License:
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2.1,
|
||||||
|
// as published by the Free Software Foundation. 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#ifndef I_RIG_FREQUENCY_CONTROLLER_H
|
||||||
|
#define I_RIG_FREQUENCY_CONTROLLER_H
|
||||||
|
|
||||||
|
#include "IRigController.h"
|
||||||
|
|
||||||
|
class IRigFrequencyController : virtual public IRigController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Mode
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
|
||||||
|
USB,
|
||||||
|
DIGU,
|
||||||
|
LSB,
|
||||||
|
DIGL,
|
||||||
|
FM,
|
||||||
|
DIGFM,
|
||||||
|
AM,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~IRigFrequencyController() = default;
|
||||||
|
|
||||||
|
// Event handlers that are called by implementers of this interface.
|
||||||
|
EventHandler<IRigFrequencyController*, uint64_t, Mode> onFreqModeChange;
|
||||||
|
|
||||||
|
virtual void setFrequency(uint64_t frequency) = 0;
|
||||||
|
virtual void setMode(Mode mode) = 0;
|
||||||
|
virtual void requestCurrentFrequencyMode() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IRigFrequencyController() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // I_RIG_FREQUENCY_CONTROLLER_H
|
|
@ -0,0 +1,42 @@
|
||||||
|
//=========================================================================
|
||||||
|
// Name: IRigPttController.h
|
||||||
|
// Purpose: Interface for control of PTT on radios.
|
||||||
|
//
|
||||||
|
// Authors: Mooneer Salem
|
||||||
|
// License:
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2.1,
|
||||||
|
// as published by the Free Software Foundation. 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#ifndef I_RIG_PTT_CONTROLLER_H
|
||||||
|
#define I_RIG_PTT_CONTROLLER_H
|
||||||
|
|
||||||
|
#include "IRigController.h"
|
||||||
|
|
||||||
|
class IRigPttController : virtual public IRigController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IRigPttController() = default;
|
||||||
|
|
||||||
|
// Event handlers that are called by implementers of this interface.
|
||||||
|
EventHandler<IRigPttController*, bool> onPttChange;
|
||||||
|
|
||||||
|
virtual void ptt(bool state) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IRigPttController() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // I_RIG_PTT_CONTROLLER_H
|
|
@ -0,0 +1,3 @@
|
||||||
|
add_library(fdv_util STATIC
|
||||||
|
ThreadedObject.cpp
|
||||||
|
)
|
|
@ -0,0 +1,68 @@
|
||||||
|
//=========================================================================
|
||||||
|
// Name: EventHandler.h
|
||||||
|
// Purpose: List of functions that handle an event
|
||||||
|
//
|
||||||
|
// Authors: Mooneer Salem
|
||||||
|
// License:
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2.1,
|
||||||
|
// as published by the Free Software Foundation. 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#ifndef EVENT_HANDLER_H
|
||||||
|
#define EVENT_HANDLER_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
template<typename... FnArgs>
|
||||||
|
class EventHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using FnType = std::function<void(FnArgs...)>;
|
||||||
|
|
||||||
|
EventHandler() = default;
|
||||||
|
virtual ~EventHandler() = default;
|
||||||
|
|
||||||
|
void operator() (FnArgs... args);
|
||||||
|
EventHandler<FnArgs...>& operator+=(FnType fn) const;
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<FnType> fnList_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... FnArgs>
|
||||||
|
void EventHandler<FnArgs...>::operator() (FnArgs... args)
|
||||||
|
{
|
||||||
|
for (auto& fn : fnList_)
|
||||||
|
{
|
||||||
|
fn(args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... FnArgs>
|
||||||
|
EventHandler<FnArgs...>& EventHandler<FnArgs...>::operator+=(FnType fn) const
|
||||||
|
{
|
||||||
|
fnList_.push_back(fn);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... FnArgs>
|
||||||
|
void EventHandler<FnArgs...>::clear()
|
||||||
|
{
|
||||||
|
fnList_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // EVENT_HANDLER_H
|
|
@ -0,0 +1,72 @@
|
||||||
|
//=========================================================================
|
||||||
|
// Name: ThreadedObject.cpp
|
||||||
|
// Purpose: Wrapper to allow class to execute in its own thread.
|
||||||
|
//
|
||||||
|
// Authors: Mooneer Salem
|
||||||
|
// License:
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2.1,
|
||||||
|
// as published by the Free Software Foundation. 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#include "ThreadedObject.h"
|
||||||
|
|
||||||
|
ThreadedObject::ThreadedObject()
|
||||||
|
: isDestroying_(false),
|
||||||
|
objectThread_(std::bind(&ThreadedObject::eventLoop_, this))
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadedObject::~ThreadedObject()
|
||||||
|
{
|
||||||
|
isDestroying_ = true;
|
||||||
|
eventQueueCV_.notify_one();
|
||||||
|
objectThread_.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadedObject::enqueue_(std::function<void()> fn)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(eventQueueMutex_);
|
||||||
|
eventQueue_.push_back(fn);
|
||||||
|
eventQueueCV_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadedObject::eventLoop_()
|
||||||
|
{
|
||||||
|
while (!isDestroying_)
|
||||||
|
{
|
||||||
|
std::function<void()> fn;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(eventQueueMutex_);
|
||||||
|
eventQueueCV_.wait(lk, [&]() {
|
||||||
|
return isDestroying_ || eventQueue_.size() > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDestroying_)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn = eventQueue_[0];
|
||||||
|
eventQueue_.erase(eventQueue_.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fn)
|
||||||
|
{
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
//=========================================================================
|
||||||
|
// Name: ThreadedObject.h
|
||||||
|
// Purpose: Wrapper to allow class to execute in its own thread.
|
||||||
|
//
|
||||||
|
// Authors: Mooneer Salem
|
||||||
|
// License:
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2.1,
|
||||||
|
// as published by the Free Software Foundation. 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#ifndef THREADED_OBJECT_H
|
||||||
|
#define THREADED_OBJECT_H
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class ThreadedObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ThreadedObject();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ThreadedObject();
|
||||||
|
|
||||||
|
void enqueue_(std::function<void()> fn);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isDestroying_;
|
||||||
|
std::thread objectThread_;
|
||||||
|
std::vector<std::function<void()> > eventQueue_;
|
||||||
|
std::mutex eventQueueMutex_;
|
||||||
|
std::condition_variable eventQueueCV_;
|
||||||
|
|
||||||
|
void eventLoop_();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // THREADED_OBJECT_H
|
Loading…
Reference in New Issue