feat(dvk): key the DATA input, not the microphone
From a TS-590SG report: the voice keyer played through the rig's USB codec and the radio transmitted silence. Its manual says why — 'TX P1, 0: SEND (normal transmission using the MIC input), 1: DATA SEND (ACC2/USB input)' — and OpsLog only ever sent the bare TX, so the radio dutifully opened a front microphone nobody was speaking into. An option on the audio page, shown for CAT keying, says where the keyer's audio actually arrives; the manager routes it to a backend that draws the distinction and falls back to the ordinary key for every rig where one PTT is all there is. Test PTT goes down the same path, so it tests what will happen rather than something adjacent.
This commit is contained in:
@@ -195,6 +195,7 @@ const (
|
|||||||
keyAudioQSOPlayGain = "audio.qso_play_gain" // QSO-recording playback level %
|
keyAudioQSOPlayGain = "audio.qso_play_gain" // QSO-recording playback level %
|
||||||
keyAudioPTTMethod = "audio.ptt_method" // "none" (VOX) | "rts" | "dtr"
|
keyAudioPTTMethod = "audio.ptt_method" // "none" (VOX) | "rts" | "dtr"
|
||||||
keyAudioPTTPort = "audio.ptt_port" // COM port for serial PTT
|
keyAudioPTTPort = "audio.ptt_port" // COM port for serial PTT
|
||||||
|
keyAudioPTTData = "audio.ptt_data" // keyer audio arrives on the rig DATA/USB input
|
||||||
keyAudioFormat = "audio.qso_format" // "wav" | "mp3"
|
keyAudioFormat = "audio.qso_format" // "wav" | "mp3"
|
||||||
keyAudioFromGain = "audio.from_gain" // From Radio (RX) mix level, percent
|
keyAudioFromGain = "audio.from_gain" // From Radio (RX) mix level, percent
|
||||||
keyAudioMicGain = "audio.mic_gain" // mic mix level, percent
|
keyAudioMicGain = "audio.mic_gain" // mic mix level, percent
|
||||||
@@ -8529,11 +8530,15 @@ type AudioSettings struct {
|
|||||||
PrerollSeconds int `json:"preroll_seconds"` // rolling pre-roll (default 8)
|
PrerollSeconds int `json:"preroll_seconds"` // rolling pre-roll (default 8)
|
||||||
PTTMethod string `json:"ptt_method"` // "none" (VOX) | "rts" | "dtr"
|
PTTMethod string `json:"ptt_method"` // "none" (VOX) | "rts" | "dtr"
|
||||||
PTTPort string `json:"ptt_port"` // COM port for serial PTT
|
PTTPort string `json:"ptt_port"` // COM port for serial PTT
|
||||||
Format string `json:"format"` // "wav" | "mp3"
|
// PTTData: the keyer's audio reaches the radio on its DATA/USB input, not
|
||||||
FromGain int `json:"from_gain"` // From Radio (RX) mix level %, default 100
|
// the microphone socket. CAT keying only — it changes which transmit
|
||||||
MicGain int `json:"mic_gain"` // mic mix level %, default 100
|
// command is sent (a Kenwood TS-590 takes TX1 instead of TX).
|
||||||
TXGain int `json:"tx_gain"` // voice-keyer playback level %, default 100
|
PTTData bool `json:"ptt_data"`
|
||||||
QSOPlayGain int `json:"qso_play_gain"` // QSO-recording playback level %, default 100
|
Format string `json:"format"` // "wav" | "mp3"
|
||||||
|
FromGain int `json:"from_gain"` // From Radio (RX) mix level %, default 100
|
||||||
|
MicGain int `json:"mic_gain"` // mic mix level %, default 100
|
||||||
|
TXGain int `json:"tx_gain"` // voice-keyer playback level %, default 100
|
||||||
|
QSOPlayGain int `json:"qso_play_gain"` // QSO-recording playback level %, default 100
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListAudioInputDevices / ListAudioOutputDevices enumerate WASAPI endpoints
|
// ListAudioInputDevices / ListAudioOutputDevices enumerate WASAPI endpoints
|
||||||
@@ -8590,7 +8595,7 @@ func (a *App) GetAudioSettings() (AudioSettings, error) {
|
|||||||
}
|
}
|
||||||
m, err := a.settings.GetMany(a.ctx,
|
m, err := a.settings.GetMany(a.ctx,
|
||||||
keyAudioFromRadio, keyAudioToRadio, keyAudioRecDevice, keyAudioListenDevice,
|
keyAudioFromRadio, keyAudioToRadio, keyAudioRecDevice, keyAudioListenDevice,
|
||||||
keyAudioQSORecord, keyAudioQSODir, keyAudioPreroll, keyAudioPTTMethod, keyAudioPTTPort, keyAudioFormat,
|
keyAudioQSORecord, keyAudioQSODir, keyAudioPreroll, keyAudioPTTMethod, keyAudioPTTPort, keyAudioPTTData, keyAudioFormat,
|
||||||
keyAudioFromGain, keyAudioMicGain, keyAudioTXGain, keyAudioQSOPlayGain)
|
keyAudioFromGain, keyAudioMicGain, keyAudioTXGain, keyAudioQSOPlayGain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return out, err
|
return out, err
|
||||||
@@ -8602,6 +8607,7 @@ func (a *App) GetAudioSettings() (AudioSettings, error) {
|
|||||||
out.PTTMethod = v
|
out.PTTMethod = v
|
||||||
}
|
}
|
||||||
out.PTTPort = m[keyAudioPTTPort]
|
out.PTTPort = m[keyAudioPTTPort]
|
||||||
|
out.PTTData = m[keyAudioPTTData] == "1"
|
||||||
out.FromRadio = m[keyAudioFromRadio]
|
out.FromRadio = m[keyAudioFromRadio]
|
||||||
out.ToRadio = m[keyAudioToRadio]
|
out.ToRadio = m[keyAudioToRadio]
|
||||||
out.RecordingDevice = m[keyAudioRecDevice]
|
out.RecordingDevice = m[keyAudioRecDevice]
|
||||||
@@ -8672,6 +8678,7 @@ func (a *App) SaveAudioSettings(s AudioSettings) error {
|
|||||||
keyAudioPreroll: strconv.Itoa(s.PrerollSeconds),
|
keyAudioPreroll: strconv.Itoa(s.PrerollSeconds),
|
||||||
keyAudioPTTMethod: pttMethod,
|
keyAudioPTTMethod: pttMethod,
|
||||||
keyAudioPTTPort: strings.TrimSpace(s.PTTPort),
|
keyAudioPTTPort: strings.TrimSpace(s.PTTPort),
|
||||||
|
keyAudioPTTData: boolStr(s.PTTData),
|
||||||
keyAudioFormat: format,
|
keyAudioFormat: format,
|
||||||
keyAudioFromGain: strconv.Itoa(s.FromGain),
|
keyAudioFromGain: strconv.Itoa(s.FromGain),
|
||||||
keyAudioMicGain: strconv.Itoa(s.MicGain),
|
keyAudioMicGain: strconv.Itoa(s.MicGain),
|
||||||
@@ -10599,7 +10606,7 @@ func (a *App) pttKey(cfg AudioSettings) error {
|
|||||||
if a.cat == nil {
|
if a.cat == nil {
|
||||||
return fmt.Errorf("CAT not initialized")
|
return fmt.Errorf("CAT not initialized")
|
||||||
}
|
}
|
||||||
if err := a.cat.SetPTT(true); err != nil {
|
if err := a.cat.SetPTTSource(true, cfg.PTTData); err != nil {
|
||||||
applog.Printf("ptt: CAT SetPTT failed: %v", err)
|
applog.Printf("ptt: CAT SetPTT failed: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -3,10 +3,12 @@
|
|||||||
"version": "0.27.9",
|
"version": "0.27.9",
|
||||||
"date": "",
|
"date": "",
|
||||||
"en": [
|
"en": [
|
||||||
"FT decodes warn when the decoding application announces a band the radio is not on — the signature of a lost CAT link, where it repeats the last frequency it knew and every decode after that carries a stale band. Nothing downstream could tell, so NEW BAND was being judged against a band the operator had left. OpsLog says it rather than deciding: a second receiver on another band is a real setup, and it costs that one only a line to read past."
|
"FT decodes warn when the decoding application announces a band the radio is not on — the signature of a lost CAT link, where it repeats the last frequency it knew and every decode after that carries a stale band. Nothing downstream could tell, so NEW BAND was being judged against a band the operator had left. OpsLog says it rather than deciding: a second receiver on another band is a real setup, and it costs that one only a line to read past.",
|
||||||
|
"Voice keyer with CAT keying: an option saying the keyer’s audio arrives on the radio’s DATA / USB input rather than the microphone socket. A Kenwood TS-590 has two transmit commands — TX opens the front mic, TX1 the rear ACC2/USB — so a keyer playing through the rig’s own sound card was transmitting dead air while the radio listened to a microphone nobody was speaking into. Rigs with a single PTT are unaffected, and the Test PTT button exercises the same path."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Les FT decodes signalent quand le logiciel de décodage annonce une bande sur laquelle la radio n’est pas — la signature d’une liaison CAT perdue, où il répète la dernière fréquence connue et où tous les décodages suivants portent une bande périmée. Rien en aval ne pouvait s’en apercevoir : NOUVELLE BANDE était donc jugé sur une bande quittée. OpsLog le dit sans décider à votre place : un second récepteur sur une autre bande est une configuration légitime, et il ne lui en coûte qu’une ligne à ignorer."
|
"Les FT decodes signalent quand le logiciel de décodage annonce une bande sur laquelle la radio n’est pas — la signature d’une liaison CAT perdue, où il répète la dernière fréquence connue et où tous les décodages suivants portent une bande périmée. Rien en aval ne pouvait s’en apercevoir : NOUVELLE BANDE était donc jugé sur une bande quittée. OpsLog le dit sans décider à votre place : un second récepteur sur une autre bande est une configuration légitime, et il ne lui en coûte qu’une ligne à ignorer.",
|
||||||
|
"Voice keyer avec PTT CAT : une option indiquant que l’audio du keyer arrive sur l’entrée DATA / USB de la radio et non sur la prise micro. Un Kenwood TS-590 a deux commandes d’émission — TX ouvre le micro de face avant, TX1 l’ACC2/USB — si bien qu’un keyer jouant par la carte son du poste émettait dans le vide pendant que la radio écoutait un micro devant lequel personne ne parlait. Les postes à PTT unique ne sont pas concernés, et le bouton Test PTT emprunte le même chemin."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1702,13 +1702,13 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged
|
|||||||
type AudioSettings = {
|
type AudioSettings = {
|
||||||
from_radio: string; to_radio: string; recording_device: string; listening_device: string;
|
from_radio: string; to_radio: string; recording_device: string; listening_device: string;
|
||||||
qso_record: boolean; qso_dir: string; preroll_seconds: number;
|
qso_record: boolean; qso_dir: string; preroll_seconds: number;
|
||||||
ptt_method: 'none' | 'cat' | 'rts' | 'dtr'; ptt_port: string; format: 'wav' | 'mp3';
|
ptt_method: 'none' | 'cat' | 'rts' | 'dtr'; ptt_port: string; ptt_data?: boolean; format: 'wav' | 'mp3';
|
||||||
from_gain: number; mic_gain: number; tx_gain: number; qso_play_gain: number;
|
from_gain: number; mic_gain: number; tx_gain: number; qso_play_gain: number;
|
||||||
};
|
};
|
||||||
type AudioDev = { id: string; name: string; default: boolean };
|
type AudioDev = { id: string; name: string; default: boolean };
|
||||||
const [audioCfg, setAudioCfg] = useState<AudioSettings>({
|
const [audioCfg, setAudioCfg] = useState<AudioSettings>({
|
||||||
from_radio: '', to_radio: '', recording_device: '', listening_device: '',
|
from_radio: '', to_radio: '', recording_device: '', listening_device: '',
|
||||||
qso_record: false, qso_dir: '', preroll_seconds: 8, ptt_method: 'none', ptt_port: '', format: 'wav',
|
qso_record: false, qso_dir: '', preroll_seconds: 8, ptt_method: 'none', ptt_port: '', ptt_data: false, format: 'wav',
|
||||||
from_gain: 100, mic_gain: 100, tx_gain: 100, qso_play_gain: 100,
|
from_gain: 100, mic_gain: 100, tx_gain: 100, qso_play_gain: 100,
|
||||||
});
|
});
|
||||||
const [audioInputs, setAudioInputs] = useState<AudioDev[]>([]);
|
const [audioInputs, setAudioInputs] = useState<AudioDev[]>([]);
|
||||||
@@ -7251,6 +7251,16 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{audioCfg.ptt_method === 'cat' && (
|
||||||
|
<>
|
||||||
|
<span />
|
||||||
|
<label className="flex items-start gap-2 text-sm cursor-pointer" title={t('aud.pttDataHint')}>
|
||||||
|
<Checkbox className="mt-0.5" checked={!!audioCfg.ptt_data}
|
||||||
|
onCheckedChange={(c) => setAudioField({ ptt_data: !!c })} />
|
||||||
|
<span>{t('aud.pttData')}</span>
|
||||||
|
</label>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{(audioCfg.ptt_method === 'rts' || audioCfg.ptt_method === 'dtr') && (
|
{(audioCfg.ptt_method === 'rts' || audioCfg.ptt_method === 'dtr') && (
|
||||||
<>
|
<>
|
||||||
<Label className="text-sm">{t('aud.pttPort')}</Label>
|
<Label className="text-sm">{t('aud.pttPort')}</Label>
|
||||||
|
|||||||
@@ -535,7 +535,7 @@ const en: Dict = {
|
|||||||
'aud.preroll': 'Pre-roll (seconds)', 'aud.format': 'File format', 'aud.wav': 'WAV (lossless, larger)', 'aud.mp3': 'MP3 (compressed, small)',
|
'aud.preroll': 'Pre-roll (seconds)', 'aud.format': 'File format', 'aud.wav': 'WAV (lossless, larger)', 'aud.mp3': 'MP3 (compressed, small)',
|
||||||
'aud.fromLevel': 'From Radio level', 'aud.txLevel': 'Voice keyer level', 'aud.txLevelHint': 'Level of the recorded messages sent to the radio. Raise it if your voice keyer is much quieter than your microphone; Play previews at this same level. If the radio transmits almost nothing, its modulation source is still the front microphone: on an FTDX10 set MENU → SSB MOD SOURCE to REAR (the USB input).', 'aud.micLevel': 'Mic level', 'aud.qsoPlayLevel': 'QSO playback level', 'aud.levelHint': 'If your voice is louder than the station, lower Mic level.',
|
'aud.fromLevel': 'From Radio level', 'aud.txLevel': 'Voice keyer level', 'aud.txLevelHint': 'Level of the recorded messages sent to the radio. Raise it if your voice keyer is much quieter than your microphone; Play previews at this same level. If the radio transmits almost nothing, its modulation source is still the front microphone: on an FTDX10 set MENU → SSB MOD SOURCE to REAR (the USB input).', 'aud.micLevel': 'Mic level', 'aud.qsoPlayLevel': 'QSO playback level', 'aud.levelHint': 'If your voice is louder than the station, lower Mic level.',
|
||||||
'aud.autoSend': 'Auto-send the recording to the station by e-mail when I log a QSO',
|
'aud.autoSend': 'Auto-send the recording to the station by e-mail when I log a QSO',
|
||||||
'aud.dvkTitle': 'Voice keyer messages (F1–F12)', 'aud.deleteMsg': 'Delete this message', 'aud.pttMethod': 'PTT method', 'aud.pttNone': 'None (VOX)', 'aud.pttCat': 'CAT (the radio link)', 'aud.pttRts': 'Serial RTS', 'aud.pttDtr': 'Serial DTR',
|
'aud.dvkTitle': 'Voice keyer messages (F1–F12)', 'aud.deleteMsg': 'Delete this message', 'aud.pttData': 'The keyer’s audio arrives on the radio’s DATA / USB input', 'aud.pttDataHint': 'Changes which transmit command is sent: a Kenwood TS-590 takes TX1 (ACC2/USB) instead of TX (front microphone). Without it the radio transmits while listening to a microphone nobody is speaking into. Rigs with a single PTT ignore this.', 'aud.pttMethod': 'PTT method', 'aud.pttNone': 'None (VOX)', 'aud.pttCat': 'CAT (the radio link)', 'aud.pttRts': 'Serial RTS', 'aud.pttDtr': 'Serial DTR',
|
||||||
'aud.testPtt': 'Test PTT', 'aud.pttPort': 'PTT COM port', 'aud.pickPort': 'Pick a COM port', 'aud.selectPort': '— select —', 'aud.refresh': 'Refresh',
|
'aud.testPtt': 'Test PTT', 'aud.pttPort': 'PTT COM port', 'aud.pickPort': 'Pick a COM port', 'aud.selectPort': '— select —', 'aud.refresh': 'Refresh',
|
||||||
'aud.msgPlaceholder': 'Message {n} label (CQ, report, 73…)', 'aud.holdRec': '● Hold to rec', 'aud.recordingNow': '● Recording…', 'aud.play': '▶ Play', 'aud.stop': '■ Stop',
|
'aud.msgPlaceholder': 'Message {n} label (CQ, report, 73…)', 'aud.holdRec': '● Hold to rec', 'aud.recordingNow': '● Recording…', 'aud.play': '▶ Play', 'aud.stop': '■ Stop',
|
||||||
'aud.errPttTest': 'PTT test: ', 'aud.errRecord': 'Record: ', 'aud.errSave': 'Save: ', 'aud.errPlay': 'Play: ',
|
'aud.errPttTest': 'PTT test: ', 'aud.errRecord': 'Record: ', 'aud.errSave': 'Save: ', 'aud.errPlay': 'Play: ',
|
||||||
@@ -1037,7 +1037,7 @@ const fr: Dict = {
|
|||||||
'aud.preroll': 'Pré-enregistrement (secondes)', 'aud.format': 'Format de fichier', 'aud.wav': 'WAV (sans perte, plus volumineux)', 'aud.mp3': 'MP3 (compressé, léger)',
|
'aud.preroll': 'Pré-enregistrement (secondes)', 'aud.format': 'Format de fichier', 'aud.wav': 'WAV (sans perte, plus volumineux)', 'aud.mp3': 'MP3 (compressé, léger)',
|
||||||
'aud.fromLevel': 'Niveau depuis la radio', 'aud.txLevel': 'Niveau du voice keyer', 'aud.txLevelHint': "Niveau des messages enregistrés envoyés à la radio. Augmentez-le si votre voice keyer est bien plus faible que votre micro ; Lire fait entendre ce même niveau. Si la radio n'émet presque rien, c'est que sa source de modulation est restée le micro de façade : sur un FTDX10, réglez MENU → SSB MOD SOURCE sur REAR (l'entrée USB).", 'aud.micLevel': 'Niveau micro', 'aud.qsoPlayLevel': 'Niveau de relecture QSO', 'aud.levelHint': 'Si votre voix est plus forte que la station, baissez le niveau micro.',
|
'aud.fromLevel': 'Niveau depuis la radio', 'aud.txLevel': 'Niveau du voice keyer', 'aud.txLevelHint': "Niveau des messages enregistrés envoyés à la radio. Augmentez-le si votre voice keyer est bien plus faible que votre micro ; Lire fait entendre ce même niveau. Si la radio n'émet presque rien, c'est que sa source de modulation est restée le micro de façade : sur un FTDX10, réglez MENU → SSB MOD SOURCE sur REAR (l'entrée USB).", 'aud.micLevel': 'Niveau micro', 'aud.qsoPlayLevel': 'Niveau de relecture QSO', 'aud.levelHint': 'Si votre voix est plus forte que la station, baissez le niveau micro.',
|
||||||
'aud.autoSend': "Envoyer automatiquement l'enregistrement à la station par e-mail lorsque j'enregistre un QSO",
|
'aud.autoSend': "Envoyer automatiquement l'enregistrement à la station par e-mail lorsque j'enregistre un QSO",
|
||||||
'aud.dvkTitle': 'Messages du manipulateur vocal (F1–F12)', 'aud.deleteMsg': 'Supprimer ce message', 'aud.pttMethod': 'Méthode PTT', 'aud.pttNone': 'Aucune (VOX)', 'aud.pttCat': 'CAT (la liaison radio)', 'aud.pttRts': 'RTS série', 'aud.pttDtr': 'DTR série',
|
'aud.dvkTitle': 'Messages du manipulateur vocal (F1–F12)', 'aud.deleteMsg': 'Supprimer ce message', 'aud.pttData': 'L’audio du keyer arrive sur l’entrée DATA / USB de la radio', 'aud.pttDataHint': 'Change la commande d’émission envoyée : un Kenwood TS-590 attend TX1 (ACC2/USB) au lieu de TX (micro de face avant). Sans cela la radio émet en écoutant un micro devant lequel personne ne parle. Les postes à PTT unique l’ignorent.', 'aud.pttMethod': 'Méthode PTT', 'aud.pttNone': 'Aucune (VOX)', 'aud.pttCat': 'CAT (la liaison radio)', 'aud.pttRts': 'RTS série', 'aud.pttDtr': 'DTR série',
|
||||||
'aud.testPtt': 'Tester le PTT', 'aud.pttPort': 'Port COM du PTT', 'aud.pickPort': 'Choisir un port COM', 'aud.selectPort': '— choisir —', 'aud.refresh': 'Actualiser',
|
'aud.testPtt': 'Tester le PTT', 'aud.pttPort': 'Port COM du PTT', 'aud.pickPort': 'Choisir un port COM', 'aud.selectPort': '— choisir —', 'aud.refresh': 'Actualiser',
|
||||||
'aud.msgPlaceholder': 'Libellé du message {n} (CQ, report, 73…)', 'aud.holdRec': '● Maintenir pour enreg.', 'aud.recordingNow': '● Enregistrement…', 'aud.play': '▶ Lire', 'aud.stop': '■ Arrêter',
|
'aud.msgPlaceholder': 'Libellé du message {n} (CQ, report, 73…)', 'aud.holdRec': '● Maintenir pour enreg.', 'aud.recordingNow': '● Enregistrement…', 'aud.play': '▶ Lire', 'aud.stop': '■ Arrêter',
|
||||||
'aud.errPttTest': 'Test PTT : ', 'aud.errRecord': 'Enregistrement : ', 'aud.errSave': 'Sauvegarde : ', 'aud.errPlay': 'Lecture : ',
|
'aud.errPttTest': 'Test PTT : ', 'aud.errRecord': 'Enregistrement : ', 'aud.errSave': 'Sauvegarde : ', 'aud.errPlay': 'Lecture : ',
|
||||||
|
|||||||
@@ -1924,6 +1924,7 @@ export namespace main {
|
|||||||
preroll_seconds: number;
|
preroll_seconds: number;
|
||||||
ptt_method: string;
|
ptt_method: string;
|
||||||
ptt_port: string;
|
ptt_port: string;
|
||||||
|
ptt_data: boolean;
|
||||||
format: string;
|
format: string;
|
||||||
from_gain: number;
|
from_gain: number;
|
||||||
mic_gain: number;
|
mic_gain: number;
|
||||||
@@ -1945,6 +1946,7 @@ export namespace main {
|
|||||||
this.preroll_seconds = source["preroll_seconds"];
|
this.preroll_seconds = source["preroll_seconds"];
|
||||||
this.ptt_method = source["ptt_method"];
|
this.ptt_method = source["ptt_method"];
|
||||||
this.ptt_port = source["ptt_port"];
|
this.ptt_port = source["ptt_port"];
|
||||||
|
this.ptt_data = source["ptt_data"];
|
||||||
this.format = source["format"];
|
this.format = source["format"];
|
||||||
this.from_gain = source["from_gain"];
|
this.from_gain = source["from_gain"];
|
||||||
this.mic_gain = source["mic_gain"];
|
this.mic_gain = source["mic_gain"];
|
||||||
|
|||||||
@@ -256,6 +256,33 @@ func (m *Manager) SetPTT(on bool) error {
|
|||||||
return m.exec(func(b Backend) error { return b.SetPTT(on) })
|
return m.exec(func(b Backend) error { return b.SetPTT(on) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dataPTTSetter is implemented by a backend that can key the DATA input rather
|
||||||
|
// than the microphone. A Kenwood TS-590 has two transmit commands and takes its
|
||||||
|
// audio from a different socket for each: TX (or TX0) opens the front mic, TX1
|
||||||
|
// the rear ACC2/USB. Send the wrong one and the radio transmits in silence,
|
||||||
|
// because the audio arriving on USB is simply not the input it is listening to.
|
||||||
|
type dataPTTSetter interface {
|
||||||
|
SetPTTData(on bool) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPTTSource keys the transmitter, saying WHERE the audio is coming from.
|
||||||
|
//
|
||||||
|
// data=true means "the audio reaches the radio on its data/USB input" — what a
|
||||||
|
// voice keyer playing through the rig's own sound card needs. A backend that
|
||||||
|
// draws no distinction (every rig where one PTT is all there is) falls back to
|
||||||
|
// the ordinary key, so nothing changes for it.
|
||||||
|
func (m *Manager) SetPTTSource(on, data bool) error {
|
||||||
|
if !data {
|
||||||
|
return m.SetPTT(on)
|
||||||
|
}
|
||||||
|
return m.exec(func(b Backend) error {
|
||||||
|
if d, ok := b.(dataPTTSetter); ok {
|
||||||
|
return d.SetPTTData(on)
|
||||||
|
}
|
||||||
|
return b.SetPTT(on)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// splitSetter is implemented by the backends that can arm split AND place the
|
// splitSetter is implemented by the backends that can arm split AND place the
|
||||||
// transmit frequency. Both together: arming without setting the dial transmits
|
// transmit frequency. Both together: arming without setting the dial transmits
|
||||||
// on whatever the transmit VFO happened to hold, which is worse than refusing.
|
// on whatever the transmit VFO happened to hold, which is worse than refusing.
|
||||||
|
|||||||
@@ -632,6 +632,28 @@ func (k *Kenwood) SetPTT(on bool) error {
|
|||||||
return k.write("RX;")
|
return k.write("RX;")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPTTData keys the transmitter on the DATA input: TX1 on a TS-590, which is
|
||||||
|
// ACC2/USB rather than the front microphone. The radio's own manual is explicit
|
||||||
|
// that the parameter chooses the input — "0: SEND (normal transmission using
|
||||||
|
// the MIC input), 1: DATA SEND (ACC2/USB input)" — so a voice keyer playing
|
||||||
|
// into the rig's USB codec has to say TX1 or it transmits dead air while the
|
||||||
|
// radio listens to a microphone nobody is speaking into.
|
||||||
|
//
|
||||||
|
// Unkeying is the same RX either way; there is no data-flavoured stop.
|
||||||
|
func (k *Kenwood) SetPTTData(on bool) error {
|
||||||
|
k.mu.Lock()
|
||||||
|
defer k.mu.Unlock()
|
||||||
|
if k.port == nil {
|
||||||
|
return fmt.Errorf("kenwood: not connected")
|
||||||
|
}
|
||||||
|
k.tx = on
|
||||||
|
if on {
|
||||||
|
k.txAt = time.Now()
|
||||||
|
return k.write("TX1;")
|
||||||
|
}
|
||||||
|
return k.write("RX;")
|
||||||
|
}
|
||||||
|
|
||||||
func (k *Kenwood) write(cmd string) error {
|
func (k *Kenwood) write(cmd string) error {
|
||||||
if k.port == nil {
|
if k.port == nil {
|
||||||
return fmt.Errorf("kenwood: not connected")
|
return fmt.Errorf("kenwood: not connected")
|
||||||
|
|||||||
Reference in New Issue
Block a user