Add support for FGCom multiple radio support
PTT now uses an int channel number (0 means not pressed, 1 = comm radio 1 (index [0]),etc...) /comm-radio-selected is the default comm channel to use. This should usually be the same as will be set by PTT into /controls/radios/comm-ptt However PTT will switch the FG comm inbound and outbound frequency to whichever radio was PTT'd. New properties also set in multi-player to indicate the transmission frequency and normalised power (currently just set to 1.0) 13001(int) : sim/multiplay/comm-transmit-frequency-hz 13002(short-norm) : sim/multiplay/comm-transmit-power-norm
This commit is contained in:
parent
a9761bb3ba
commit
b42969ae91
3 changed files with 159 additions and 117 deletions
|
@ -121,6 +121,7 @@ const int EMESARYBRIDGETYPE_BASE = 12200;
|
|||
const int EMESARYBRIDGE_BASE = 12000;
|
||||
const int V2018_3_BASE = 13000;
|
||||
const int FALLBACK_MODEL_ID = 13000;
|
||||
const int V2019_3_BASE = 13001;
|
||||
|
||||
/*
|
||||
* definition of properties that are to be transmitted.
|
||||
|
@ -665,6 +666,9 @@ static const IdPropertyList sIdPropertyList[] = {
|
|||
{ EMESARYBRIDGETYPE_BASE + 29, "sim/multiplay/emesary/bridge-type[29]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL },
|
||||
|
||||
{ FALLBACK_MODEL_ID, "sim/model/fallback-model-index", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL },
|
||||
{ V2019_3_BASE, "sim/multiplay/comm-transmit-frequency-hz", simgear::props::INT, TT_INT, V1_1_2_PROP_ID, NULL, NULL },
|
||||
{ V2019_3_BASE+1, "sim/multiplay/comm-transmit-power-norm", simgear::props::INT, TT_SHORT_FLOAT_NORM , V1_1_2_PROP_ID, NULL, NULL },
|
||||
// Add new MP properties here
|
||||
};
|
||||
/*
|
||||
* For the 2017.x version 2 protocol the properties are sent in two partitions,
|
||||
|
|
|
@ -97,7 +97,11 @@ FGCom::FGCom() :
|
|||
_register(true),
|
||||
_enabled(false),
|
||||
_initialized(false),
|
||||
_listener_active(0)
|
||||
_listener_active(0),
|
||||
_commFrequencyNode(nullptr),
|
||||
_ptt_node(nullptr),
|
||||
_selected_comm_node(nullptr),
|
||||
_currentCallIdent(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -128,9 +132,8 @@ void FGCom::bind()
|
|||
_username_node = reg_node->getChild( "username", 0, true );
|
||||
_password_node = reg_node->getChild( "password", 0, true );
|
||||
|
||||
_comm0_node = fgGetNode("/instrumentation/comm[0]/frequencies/selected-mhz", true);
|
||||
_comm1_node = fgGetNode("/instrumentation/comm[1]/frequencies/selected-mhz", true);
|
||||
_ptt0_node = fgGetNode("/instrumentation/comm[0]/ptt", true); //FIXME: what about /instrumentation/comm[1]/ptt ?
|
||||
_ptt_node = fgGetNode("/controls/radios/comm-ptt", true);
|
||||
_selected_comm_node = fgGetNode("/controls/radios/comm-radio-selected", true);
|
||||
_callsign_node = fgGetNode("/sim/multiplay/callsign", true);
|
||||
_text_node = fgGetNode("/sim/messages/atc", true );
|
||||
_version_node = fgGetNode("/sim/version/flightgear", true );
|
||||
|
@ -169,6 +172,9 @@ void FGCom::bind()
|
|||
if ( !_showMessages_node->hasValue() )
|
||||
_showMessages_node->setBoolValue(false);
|
||||
|
||||
_mpTransmitFrequencyNode = fgGetNode("sim/multiplay/comm-transmit-frequency-hz", 0, true);
|
||||
_mpTransmitPowerNode = fgGetNode("sim/multiplay/comm-transmit-power-norm", 0, true);
|
||||
|
||||
_selectedOutput_node->addChangeListener(this);
|
||||
_selectedInput_node->addChangeListener(this);
|
||||
_speakerLevel_node->addChangeListener(this);
|
||||
|
@ -176,9 +182,8 @@ void FGCom::bind()
|
|||
_micBoost_node->addChangeListener(this);
|
||||
_micLevel_node->addChangeListener(this);
|
||||
_enabled_node->addChangeListener(this);
|
||||
_comm0_node->addChangeListener(this);
|
||||
_comm1_node->addChangeListener(this);
|
||||
_ptt0_node->addChangeListener(this);
|
||||
_ptt_node->addChangeListener(this);
|
||||
_selected_comm_node->addChangeListener(this);
|
||||
_test_node->addChangeListener(this);
|
||||
}
|
||||
|
||||
|
@ -197,13 +202,8 @@ void FGCom::init()
|
|||
_register = _register_node->getBoolValue();
|
||||
_username = _username_node->getStringValue();
|
||||
_password = _password_node->getStringValue();
|
||||
_selectedComm = 0;
|
||||
|
||||
_currentComm0 = _comm0_node->getDoubleValue();
|
||||
_currentComm1 = _comm1_node->getDoubleValue();
|
||||
|
||||
_comm0Changed = false;
|
||||
_comm1Changed = false;
|
||||
_currentCommFrequency = 0;
|
||||
|
||||
_maxRange = MAX_RANGE;
|
||||
_minRange = MIN_RANGE;
|
||||
|
@ -317,53 +317,103 @@ void FGCom::postinit()
|
|||
iaxc_millisleep(50);
|
||||
|
||||
// Do the first call at start
|
||||
const double freq = _comm0_node->getDoubleValue();
|
||||
_currentFreqKhz = 10 * static_cast<int>(freq * 100 + 0.25);
|
||||
std::string num = computePhoneNumber(freq, getAirportCode(freq));
|
||||
if( !num.empty() ) {
|
||||
_callComm0 = iaxc_call(num.c_str());
|
||||
}
|
||||
if( _callComm0 == -1 )
|
||||
SG_LOG( SG_IO, SG_DEBUG, "FGCom: cannot call " << num.c_str() );
|
||||
setupCommFrequency();
|
||||
connectToCommFrequency();
|
||||
}
|
||||
|
||||
double FGCom::getCurrentFrequencyKhz() const {
|
||||
return 10 * static_cast<int>(_currentCommFrequency * 100 + 0.25);
|
||||
}
|
||||
|
||||
void FGCom::setupCommFrequency(int channel) {
|
||||
if (channel < 1) {
|
||||
if (_selected_comm_node != nullptr) {
|
||||
channel = _selected_comm_node->getIntValue();
|
||||
}
|
||||
}
|
||||
// always fallback to comm 1
|
||||
if (channel < 1) {
|
||||
channel = 1;
|
||||
}
|
||||
|
||||
void FGCom::updateCall(bool& changed, int& callNo, double freqMHz)
|
||||
{
|
||||
if (channel > 0)
|
||||
{
|
||||
channel--; // adjust back to zero based index.
|
||||
SGPropertyNode *commRadioNode = fgGetNode("/instrumentation/")->getChild("comm", channel, false);
|
||||
if (commRadioNode) {
|
||||
SGPropertyNode *frequencyNode = commRadioNode->getChild("frequencies");
|
||||
if (frequencyNode) {
|
||||
frequencyNode = frequencyNode->getChild("selected-mhz");
|
||||
if (frequencyNode) {
|
||||
if (_commFrequencyNode != frequencyNode) {
|
||||
if (_commFrequencyNode)
|
||||
_commFrequencyNode->removeChangeListener(this);
|
||||
_commFrequencyNode = frequencyNode;
|
||||
_commFrequencyNode->addChangeListener(this);
|
||||
}
|
||||
_currentCommFrequency = frequencyNode->getDoubleValue();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
SG_LOG(SG_IO, SG_INFO, "FGCom: setupCommFrequency node listener failed: channel " << channel);
|
||||
}
|
||||
|
||||
_currentFreqKhz = 10 * static_cast<int>(freqMHz * 100 + 0.25);
|
||||
if (_commFrequencyNode)
|
||||
_commFrequencyNode->removeChangeListener(this);
|
||||
SG_LOG(SG_IO, SG_INFO, "FGCom: setupCommFrequency invalid channel " << channel);
|
||||
|
||||
if (!changed) {
|
||||
if( !isInRange(freqMHz) ) {
|
||||
iaxc_dump_call_number(callNo);
|
||||
callNo = -1;
|
||||
return;
|
||||
} else {
|
||||
if(callNo != -1)
|
||||
_currentCommFrequency = 0;
|
||||
}
|
||||
|
||||
void FGCom::connectToCommFrequency() {
|
||||
// ensure that the current comm is still in range
|
||||
if (_currentCallFrequency && !isInRange(_currentCallFrequency)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "FGCom: call out of range of: " << _currentCallFrequency);
|
||||
_currentCallFrequency = 0;
|
||||
}
|
||||
|
||||
if (_currentCallFrequency != _currentCommFrequency || _currentCallIdent == -1) {
|
||||
if (_currentCallIdent != -1) {
|
||||
iaxc_dump_call_number(_currentCallIdent);
|
||||
SG_LOG(SG_IO, SG_INFO, "FGCom: dump_call_number " << _currentCallIdent);
|
||||
_currentCallIdent = -1;
|
||||
}
|
||||
|
||||
if (_currentCallIdent == -1)
|
||||
{
|
||||
std::string num = computePhoneNumber(_currentCommFrequency, getAirportCode(_currentCommFrequency));
|
||||
_processingTimer.stamp();
|
||||
if (!isInRange(_currentCommFrequency)) {
|
||||
if (_currentCallIdent != -1) {
|
||||
SG_LOG(SG_IO, SG_INFO, "FGCom: disconnect call as not in range " << _currentCallIdent);
|
||||
if (_currentCallIdent != -1) {
|
||||
iaxc_dump_call_number(_currentCallIdent);
|
||||
_currentCallIdent = -1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!num.empty()) {
|
||||
_currentCallIdent = iaxc_call(num.c_str());
|
||||
if (_currentCallIdent == -1)
|
||||
SG_LOG(SG_IO, SG_DEBUG, "FGCom: cannot call " << num.c_str());
|
||||
else {
|
||||
SG_LOG(SG_IO, SG_DEBUG, "FGCom: call established " << num.c_str() << " Freq: " << _currentCommFrequency);
|
||||
_currentCallFrequency = _currentCommFrequency;
|
||||
}
|
||||
}
|
||||
else
|
||||
SG_LOG(SG_IO, SG_WARN, "FGCom: frequency " << _currentCommFrequency << " does not map to valid IAX address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changed = false; // FIXME, out-params are confusing
|
||||
|
||||
if( callNo != -1 ) {
|
||||
iaxc_dump_call_number( callNo );
|
||||
callNo = -1;
|
||||
}
|
||||
|
||||
if(_p.elapsedMSec() > IAX_DELAY) {
|
||||
std::string num = computePhoneNumber(freqMHz, getAirportCode(freqMHz));
|
||||
if( !isInRange(freqMHz) )
|
||||
return;
|
||||
if( !num.empty() ) {
|
||||
callNo = iaxc_call(num.c_str());
|
||||
|
||||
if( callNo == -1 )
|
||||
SG_LOG( SG_IO, SG_DEBUG, "FGCom: cannot call " << num.c_str() );
|
||||
}
|
||||
} else {
|
||||
changed = true;
|
||||
void FGCom::updateCall()
|
||||
{
|
||||
if (_processingTimer.elapsedMSec() > IAX_DELAY) {
|
||||
_processingTimer.stamp();
|
||||
connectToCommFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,17 +421,11 @@ void FGCom::updateCall(bool& changed, int& callNo, double freqMHz)
|
|||
|
||||
void FGCom::update(double dt)
|
||||
{
|
||||
if ( !_enabled || !_initialized ) {
|
||||
if (!_enabled || !_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For now we manage FGCom for only one freq because IAXClient
|
||||
// is not able to handle multiple calls at same time.
|
||||
if( _selectedComm == 0) {
|
||||
updateCall(_comm0Changed, _callComm0, _comm0_node->getDoubleValue());
|
||||
} else {
|
||||
updateCall(_comm1Changed, _callComm0, _comm1_node->getDoubleValue());
|
||||
}
|
||||
updateCall();
|
||||
}
|
||||
|
||||
|
||||
|
@ -404,8 +448,6 @@ void FGCom::shutdown()
|
|||
static_instance = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FGCom::valueChanged(SGPropertyNode *prop)
|
||||
{
|
||||
if (prop == _enabled_node) {
|
||||
|
@ -423,26 +465,38 @@ void FGCom::valueChanged(SGPropertyNode *prop)
|
|||
return;
|
||||
}
|
||||
|
||||
if (prop == _ptt0_node && _enabled) {
|
||||
if( _ptt0_node->getIntValue() == 2 ) {
|
||||
if( _selectedComm == 0 ) {
|
||||
SG_LOG( SG_IO, SG_INFO, "FGCom: change comm source to comm[1]" );
|
||||
_comm1Changed = true;
|
||||
_selectedComm = 1;
|
||||
} else {
|
||||
SG_LOG( SG_IO, SG_INFO, "FGCom: change comm source to comm[0]" );
|
||||
_comm0Changed = true;
|
||||
_selectedComm = 0;
|
||||
if (prop == _selected_comm_node && _enabled) {
|
||||
setupCommFrequency();
|
||||
SG_LOG(SG_IO, SG_INFO, "FGCom: change comm frequency (selected node): set to " << _currentCommFrequency);
|
||||
}
|
||||
|
||||
if (prop == _commFrequencyNode && _enabled) {
|
||||
setupCommFrequency();
|
||||
SG_LOG(SG_IO, SG_INFO, "FGCom: change comm frequency (property updated): set to " << _currentCommFrequency);
|
||||
}
|
||||
|
||||
if (prop == _ptt_node && _enabled) {
|
||||
if (_ptt_node->getIntValue()) {
|
||||
// ensure that we are on the right channel by calling setupCommFrequency with the value of the PTT node.
|
||||
// the two properties for the ptt channel and the current channel should be on the same channel
|
||||
// but if not this will flip the radio for transmit and listen to whichever frequency last did a PTT
|
||||
//
|
||||
// NOTE: Probably the whole thing needs re-writing to be multi-comm capable; but fgcomm has always been a bit
|
||||
// single oriented and I don't know if it would even work (with the right logic) in multi-channel mode.
|
||||
setupCommFrequency(_ptt_node->getIntValue());
|
||||
iaxc_output_level_set(0.0);
|
||||
iaxc_input_level_set(_micLevel_node->getFloatValue()); //0.0 = min , 1.0 = max
|
||||
_mpTransmitFrequencyNode->setValue(_currentCallFrequency * 1000000);
|
||||
_mpTransmitPowerNode->setValue(1.0);
|
||||
SG_LOG(SG_IO, SG_INFO, "FGCom: PTT active: " << _currentCallFrequency);
|
||||
}
|
||||
else {
|
||||
iaxc_output_level_set(_speakerLevel_node->getFloatValue());
|
||||
iaxc_input_level_set(0.0);
|
||||
SG_LOG(SG_IO, SG_INFO, "FGCom: PTT release: " << _currentCallFrequency);
|
||||
_mpTransmitFrequencyNode->setValue(0);
|
||||
_mpTransmitPowerNode->setValue(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( _ptt0_node->getBoolValue() ) {
|
||||
iaxc_output_level_set( 0.0 );
|
||||
iaxc_input_level_set( _micLevel_node->getFloatValue() ); //0.0 = min , 1.0 = max
|
||||
} else {
|
||||
iaxc_output_level_set( _speakerLevel_node->getFloatValue() );
|
||||
iaxc_input_level_set( 0.0 );
|
||||
}
|
||||
}
|
||||
|
||||
if (prop == _test_node) {
|
||||
|
@ -492,22 +546,6 @@ void FGCom::valueChanged(SGPropertyNode *prop)
|
|||
//iaxc_input_level_set(micLevel);
|
||||
}
|
||||
|
||||
if (prop == _comm0_node) {
|
||||
if( _currentComm0 != prop->getDoubleValue() ) {
|
||||
_currentComm0 = prop->getDoubleValue();
|
||||
_p.stamp();
|
||||
_comm0Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (prop == _comm1_node) {
|
||||
if( _currentComm1 != prop->getDoubleValue() ) {
|
||||
_currentComm1 = prop->getDoubleValue();
|
||||
_p.stamp();
|
||||
_comm1Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
_listener_active--;
|
||||
}
|
||||
|
||||
|
@ -523,9 +561,9 @@ void FGCom::testMode(bool testMode)
|
|||
std::string num = computePhoneNumber(TEST_FREQ, NULL_ICAO);
|
||||
if( num.size() > 0 ) {
|
||||
iaxc_millisleep(IAX_DELAY);
|
||||
_callComm0 = iaxc_call(num.c_str());
|
||||
_currentCallIdent = iaxc_call(num.c_str());
|
||||
}
|
||||
if( _callComm0 == -1 )
|
||||
if( _currentCallIdent == -1 )
|
||||
SG_LOG( SG_IO, SG_DEBUG, "FGCom: cannot call " << num.c_str() );
|
||||
} else {
|
||||
if( _initialized ) {
|
||||
|
@ -533,7 +571,7 @@ void FGCom::testMode(bool testMode)
|
|||
iaxc_millisleep(IAX_DELAY);
|
||||
iaxc_input_level_set( 0.0 );
|
||||
iaxc_output_level_set( _speakerLevel_node->getFloatValue() );
|
||||
_callComm0 = -1;
|
||||
_currentCallIdent = -1;
|
||||
_enabled = true;
|
||||
}
|
||||
}
|
||||
|
@ -551,14 +589,14 @@ std::string FGCom::getAirportCode(const double& freq)
|
|||
SGGeod aircraftPos = globals->get_aircraft_position();
|
||||
|
||||
for(size_t i=0; i<sizeof(special_freq)/sizeof(special_freq[0]); i++) { // Check if it's a special freq
|
||||
if(special_freq[i] == _currentFreqKhz) {
|
||||
if(special_freq[i] == getCurrentFrequencyKhz()) {
|
||||
return NULL_ICAO;
|
||||
}
|
||||
}
|
||||
|
||||
flightgear::CommStation* apt = flightgear::CommStation::findByFreq(_currentFreqKhz, aircraftPos);
|
||||
flightgear::CommStation* apt = flightgear::CommStation::findByFreq(getCurrentFrequencyKhz(), aircraftPos);
|
||||
if( !apt ) {
|
||||
apt = flightgear::CommStation::findByFreq(_currentFreqKhz-10, aircraftPos); // Check for 8.33KHz
|
||||
apt = flightgear::CommStation::findByFreq(getCurrentFrequencyKhz() -10, aircraftPos); // Check for 8.33KHz
|
||||
if( !apt ) {
|
||||
return std::string();
|
||||
}
|
||||
|
@ -630,7 +668,7 @@ std::string FGCom::computePhoneNumber(const double& freq, const std::string& ica
|
|||
bool FGCom::isInRange(const double &freq) const
|
||||
{
|
||||
for(size_t i=0; i<sizeof(special_freq)/sizeof(special_freq[0]); i++) { // Check if it's a special freq
|
||||
if( (special_freq[i]) == _currentFreqKhz ) {
|
||||
if( (special_freq[i]) == getCurrentFrequencyKhz()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,9 +41,9 @@ class FGCom : public SGSubsystem, public SGPropertyChangeListener
|
|||
|
||||
private:
|
||||
|
||||
SGPropertyNode_ptr _ptt0_node; // instrumentation/nav[0]/ptt
|
||||
SGPropertyNode_ptr _comm0_node; // instrumentation/comm[0]/frequencies/selected-mhz
|
||||
SGPropertyNode_ptr _comm1_node; // instrumentation/comm[1]/frequencies/selected-mhz
|
||||
SGPropertyNode_ptr _ptt_node; // PTT; nonzero int indicating channel number (instrumentation/comm/[channel-1])
|
||||
SGPropertyNode_ptr _selected_comm_node; // selected channel (fgcom); nonzero channel int indicating channel number (instrumentation/comm/[channel-1])
|
||||
SGPropertyNode_ptr _commFrequencyNode; // current comm node in use; e.g. /instrumentation/comm[0]
|
||||
SGPropertyNode_ptr _test_node; // sim/fgcom/test
|
||||
SGPropertyNode_ptr _text_node; // sim/fgcom/text
|
||||
SGPropertyNode_ptr _server_node; // sim/fgcom/server
|
||||
|
@ -64,37 +64,37 @@ class FGCom : public SGSubsystem, public SGPropertyChangeListener
|
|||
SGPropertyNode_ptr _selectedInput_node; // sim/fgcom/device-input
|
||||
SGPropertyNode_ptr _selectedOutput_node; // sim/fgcom/device-output
|
||||
SGPropertyNode_ptr _showMessages_node; // sim/fgcom/show-messages
|
||||
|
||||
SGPropertyNode_ptr _mpTransmitFrequencyNode; // sim/multiplay/comm-transmit-frequency-mhz
|
||||
SGPropertyNode_ptr _mpTransmitPowerNode; // sim/multiplay/comm-transmit-power-norm
|
||||
|
||||
|
||||
double _maxRange;
|
||||
double _minRange;
|
||||
double _currentComm0;
|
||||
double _currentComm1;
|
||||
bool _comm0Changed;
|
||||
bool _comm1Changed;
|
||||
double _currentCommFrequency;
|
||||
double _currentCallFrequency;
|
||||
bool _register;
|
||||
bool _enabled;
|
||||
bool _initialized;
|
||||
int _regId;
|
||||
int _callComm0;
|
||||
int _currentCallIdent;
|
||||
//int _callComm1;
|
||||
int _listener_active;
|
||||
int _currentFreqKhz;
|
||||
int _selectedComm;
|
||||
std::string _server;
|
||||
std::string _callsign;
|
||||
std::string _username;
|
||||
std::string _password;
|
||||
SGTimeStamp _p;
|
||||
SGTimeStamp _processingTimer;
|
||||
SGGeod _aptPos;
|
||||
|
||||
std::string computePhoneNumber(const double& freq, const std::string& icao) const;
|
||||
std::string getAirportCode(const double& freq);
|
||||
SGGeod getAirportPos(const double& freq) const;
|
||||
// SGGeod getAirportPos(const double& freq) const;
|
||||
void setupCommFrequency(int channel = -1);
|
||||
double getCurrentFrequencyKhz() const;
|
||||
bool isInRange(const double& freq) const;
|
||||
|
||||
void updateCall(bool& changed, int& callNo, double freqMHz);
|
||||
|
||||
void updateCall();
|
||||
void connectToCommFrequency();
|
||||
void testMode(bool testMode);
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue