You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Using rig-bridge the frequency of my Yaesu transceiver can be changed.
However my band specific settings (like gain) are not switching because only the frequency is send.
I adapted the code to send a band change first, wait and than change frequency.
Here the code for protocol-yaesu.js :
'use strict';
/**
protocol-yaesu.js — Yaesu CAT ASCII protocol
Covers: FT-991A, FT-891, FT-710, FT-DX10, FT-DX101, FT-5000, etc.
Commands are ASCII, semicolon-terminated.
Pure functions — all I/O is injected via serialWrite / updateState.
*/
function poll(serialWrite) {
// IF; returns frequency + mode + PTT + VFO state in a single response,
// universally supported across all FT-series radios (FT-991A, FT-891, FT-710,
// FT-DX10, etc.). Using a single command avoids the timing issues of sending
// FA; and MD0; separately and gives us PTT state for free too.
serialWrite('IF;');
}
/**
parse()
Incremental parser for Yaesu responses.
Called with semicolon-terminated strings (e.g. "IF...;")
*/
function parse(data, updateState, getState, debug) {
if (debug) console.log([Yaesu/Proto] parse: ${data});
if (!data || data.length < 2) return;
const cmd = data.substring(0, 2);
switch (cmd) {
case 'IF': {
// IF response format verified against live FT-991A:
// Cross-checked: FA; returned 438700000 Hz, found at IF positions 5-13.
// Cross-checked: MD0; returned mode 4 (FM), found '4' at IF position 21.
//
// IF [2-char sub-band] [3-char ??] [9-char freq Hz] [1 RIT sign] [4 RIT val]
// [1 RIT on] [1 XIT on] [1 mode] [1 TX/RX] [rest...]
//
// pos 2-3 (2): sub-band / display prefix → "00"
// pos 4 (1): unknown → "2"
// pos 5-13(9): VFO A frequency in Hz → "438700000" ← FA; confirmed
// pos 14 (1): RIT/XIT sign → "+"
// pos 15-18(4): RIT/XIT offset → "0000"
// pos 19 (1): RIT on/off → "0"
// pos 20 (1): XIT on/off → "0"
// pos 21 (1): mode → "4" = FM ← MD0; confirmed
// pos 22 (1): TX/RX (0=RX, 1=TX) → "0"
// pos 23-25(3): memory channel → "100"
// pos 26 (1): VFO (0=A, 1=B) → "0"
if (data.length >= 22) {
const freqStr = data.substring(5, 14); // 9-digit frequency (confirmed by FA; cross-check)
const freq = parseInt(freqStr, 10);
if (freq > 0) updateState('freq', freq);
const modeDigit = data.charAt(21); // mode confirmed by MD0; cross-check
const mode = MODES[modeDigit] || getState('mode');
updateState('mode', mode);
// PTT is intentionally NOT parsed from IF; here.
//
// The IF; TX/RX flag is at position 22, but that position is only confirmed
// on the FT-991A. On other models (FT-891, FT-710, FT-DX10, etc.) the
// "unknown" byte at position 4 may be absent, shifting all subsequent fields
// left by one — causing the memory channel digit ('1' for ch 100-199) to land
// at position 22 and trigger a false PTT=TX.
//
// PTT state is instead read exclusively from TX;/RX; auto-info responses
// (which use unambiguous 3-character format) and from explicit TX; queries
// sent at startup and in the 30-second keepalive.
}
break;
}
case 'FA': {
const freq = parseInt(data.substring(2), 10);
if (freq > 0) updateState('freq', freq);
break;
}
case 'MD': {
const modeStr = data.substring(2);
const modeDigit = modeStr.length >= 2 ? modeStr.charAt(1) : modeStr.charAt(0);
const mode = MODES[modeDigit] || getState('mode');
updateState('mode', mode);
break;
}
case 'TX':
case 'RX': {
// Handles both TX;/RX; (unsolicited) and TXn; (auto-info)
// TX0 = RX, TX1 = PTT TX, TX2 = CAT/linear TX
// A bare TX; (no digit) is ignored — don't infer TX state from absence of '0'.
if (cmd === 'RX') {
updateState('ptt', false);
} else {
const txDigit = data.length >= 3 ? data.charAt(2) : '';
if (txDigit === '0') updateState('ptt', false);
else if (txDigit === '1' || txDigit === '2') updateState('ptt', true);
// else: no digit or unrecognised — leave PTT state unchanged
}
break;
}
default: {
// Log unrecognised responses — e.g. '?' means the radio rejected the command
// (wrong baud rate, CAT not enabled, or unsupported command for this model)
if (data.trim() && debug) console.log(`[Yaesu] Unrecognised response: "${data.trim()}"`);
break;
}
function setMode(mode, serialWrite) {
let digit = MODE_REVERSE[mode];
if (!digit) digit = MODE_ALIASES[mode.toUpperCase()];
if (digit) serialWrite(MD0${digit};);
}
function setPTT(on, serialWrite) {
serialWrite(on ? 'TX1;' : 'TX0;');
}
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Using rig-bridge the frequency of my Yaesu transceiver can be changed.
However my band specific settings (like gain) are not switching because only the frequency is send.
I adapted the code to send a band change first, wait and than change frequency.
Here the code for protocol-yaesu.js :
'use strict';
/**
*/
const MODES = {
1: 'LSB',
2: 'USB',
3: 'CW',
4: 'FM',
5: 'AM',
6: 'RTTY-LSB',
7: 'CW-R',
8: 'DATA-LSB',
9: 'RTTY-USB',
A: 'DATA-FM',
B: 'FM-N',
C: 'DATA-USB',
D: 'AM-N',
E: 'C4FM',
};
const MODE_REVERSE = {};
Object.entries(MODES).forEach(([k, v]) => {
MODE_REVERSE[v] = k;
});
const MODE_ALIASES = {
USB: '2',
LSB: '1',
CW: '3',
'CW-R': '7',
FM: '4',
AM: '5',
'DATA-USB': 'C',
'DATA-LSB': '8',
RTTY: '6',
'RTTY-R': '9',
FT8: 'C',
FT4: 'C',
DIGI: 'C',
SSB: '2',
PSK: 'C',
JT65: 'C',
};
function poll(serialWrite) {
// IF; returns frequency + mode + PTT + VFO state in a single response,
// universally supported across all FT-series radios (FT-991A, FT-891, FT-710,
// FT-DX10, etc.). Using a single command avoids the timing issues of sending
// FA; and MD0; separately and gives us PTT state for free too.
serialWrite('IF;');
}
/**
*/
function parse(data, updateState, getState, debug) {
if (debug) console.log(
[Yaesu/Proto] parse: ${data});if (!data || data.length < 2) return;
const cmd = data.substring(0, 2);
switch (cmd) {
case 'IF': {
// IF response format verified against live FT-991A:
// Cross-checked: FA; returned 438700000 Hz, found at IF positions 5-13.
// Cross-checked: MD0; returned mode 4 (FM), found '4' at IF position 21.
//
// IF [2-char sub-band] [3-char ??] [9-char freq Hz] [1 RIT sign] [4 RIT val]
// [1 RIT on] [1 XIT on] [1 mode] [1 TX/RX] [rest...]
//
// pos 2-3 (2): sub-band / display prefix → "00"
// pos 4 (1): unknown → "2"
// pos 5-13(9): VFO A frequency in Hz → "438700000" ← FA; confirmed
// pos 14 (1): RIT/XIT sign → "+"
// pos 15-18(4): RIT/XIT offset → "0000"
// pos 19 (1): RIT on/off → "0"
// pos 20 (1): XIT on/off → "0"
// pos 21 (1): mode → "4" = FM ← MD0; confirmed
// pos 22 (1): TX/RX (0=RX, 1=TX) → "0"
// pos 23-25(3): memory channel → "100"
// pos 26 (1): VFO (0=A, 1=B) → "0"
if (data.length >= 22) {
const freqStr = data.substring(5, 14); // 9-digit frequency (confirmed by FA; cross-check)
const freq = parseInt(freqStr, 10);
if (freq > 0) updateState('freq', freq);
}
}
// Maps upper-edge frequency (Hz) to Yaesu BS band-select code.
// Frequencies above the last entry (70cm) are sent without a band-change first.
const BAND_MAP = [
{ max: 2_000_000, code: '00' }, // 160m
{ max: 4_000_000, code: '01' }, // 80m
{ max: 5_500_000, code: '02' }, // 60m
{ max: 7_300_000, code: '03' }, // 40m
{ max: 10_200_000, code: '04' }, // 30m
{ max: 14_350_000, code: '05' }, // 20m
{ max: 18_200_000, code: '06' }, // 17m
{ max: 21_450_000, code: '07' }, // 15m
{ max: 24_990_000, code: '08' }, // 12m
{ max: 29_700_000, code: '09' }, // 10m
{ max: 54_000_000, code: '10' }, // 6m
{ max: 148_000_000, code: '14' }, // 2m
{ max: 450_000_000, code: '15' }, // 70cm
];
function freqToBandCode(hz) {
for (const { max, code } of BAND_MAP) {
if (hz <= max) return code;
}
return null;
}
function setFreq(hz, serialWrite) {
const padded = String(Math.round(hz)).padStart(9, '0');
const bandCode = freqToBandCode(hz);
if (bandCode !== null) {
serialWrite(
BS${bandCode};);setTimeout(() => serialWrite(
FA${padded};), 100);} else {
serialWrite(
FA${padded};);}
}
function setMode(mode, serialWrite) {
let digit = MODE_REVERSE[mode];
if (!digit) digit = MODE_ALIASES[mode.toUpperCase()];
if (digit) serialWrite(
MD0${digit};);}
function setPTT(on, serialWrite) {
serialWrite(on ? 'TX1;' : 'TX0;');
}
module.exports = { poll, parse, setFreq, setMode, setPTT };
All reactions