Skip to content

PTB integration (new PACTOR mode) - #529

Open
harenber wants to merge 3 commits into
la5nta:developfrom
harenber:ptb-integration
Open

PTB integration (new PACTOR mode)#529
harenber wants to merge 3 commits into
la5nta:developfrom
harenber:ptb-integration

Conversation

@harenber

@harenber harenber commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Transport for the PACTOR-TCP-bridge. See PTB git page for details. Enables listen mode on PACTOR.

@martinhpedersen

Copy link
Copy Markdown
Member

Thanks for this PR 😊

Haven't found time to review yet, but hopefully next week.

Thank you!

@martinhpedersen
martinhpedersen self-requested a review July 21, 2026 08:42
Comment thread cfg/config.go Outdated
Comment on lines +301 to +303
// Network address of the PTB data socket (e.g. localhost:8301).
// If empty, defaults to command port + 1.
DataAddr string `json:"data_addr,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you imagine we'll ever need to set this explicitly? Maybe we can omit it, and re-consider on user requests? I usually lean towards making the API surface as small as possible 😊

Comment thread cli/connect.go
ardop: ARDOP TNC
pactor: SCS PTC modems
pactor: SCS PTC modems (legacy driver)
ptb: PTB (PACTOR-TCP-Bridge) - modern PACTOR driver

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to discuss merging ptb into the existing pactor scheme. Ideally we should have one transport per mode, and which "driver" to use should be configurable by the user. This way, connect URIs such as pactor:///HB9AK?freq=10144.4 can work regardless of the driver.

Depending on whether we want to fully deprecate ptc-go, I think we have two options:

Transport agent

We've done this for the ax25 scheme, with the concept of a "transport engine". Depending on the selected engine, the dial/listen/init picks a code path.

For ax25 I took it one step further, having ax25 serve as an alias for ax25+linux://, ax25+agwpe://, ax25+seria-tnc://. This was done in case anyone wanted to use more than one at a time. They are implemented as distinct transport schemes, and ax25:// is resolved using this function:

pat/app/connect.go

Lines 450 to 461 in 2e6a8d1

func (a *App) defaultAX25Method() string {
switch a.config.AX25.Engine {
case cfg.AX25EngineAGWPE:
return MethodAX25AGWPE
case cfg.AX25EngineSerialTNC:
return MethodAX25SerialTNC
case cfg.AX25EngineLinux:
return MethodAX25Linux
default:
panic(fmt.Sprintf("invalid ax25 engine: %s", a.config.AX25.Engine))
}
}

We could do the same here, by having pactor:// resolve to either pactor+ptb:// or pactor+serial://.

Addr vs Path fields

Another approach could be to stick withpactor:// and the config struct Pactor alone, and switch on whether the (deprecated)cfg.Pactor.Path is set. We should at the same time remove the default /dev/ttyUSB0 value of Path of course, so new users won't get the deprecated driver by default.

type Pactor struct {
	// Network address of the PTB command socket (e.g. localhost:8300).
	Addr string `json:"addr"` // NOTE: This one should probably have a default value

 	// (optional) Reference name to the Hamlib rig to control frequency and ptt.
	Rig string `json:"rig"`

	// Enable PTT control through the rig.
	PTTControl bool `json:"ptt_ctrl"`

	// Deprecated fields (using omitempty so they won't appear in new config files)
	Path string `json:"path,omitempty"`
	Baudrate int `json:"baudrate,omitempty"`
	InitScript string `json:"custom_init_script,omitempty"`
}

func (p Pactor) IsLegacy() bool { return p.Path != "" && p.Addr == "" }

If we truly want to deprecate ptc-go, I think this may be the cleanest way to do it. Once ptc-go is fully obsolete we can remove the code and are left with the intuitively named pactor:// and cfg.Pactor.


Which to pick really depends on whether we want to keep ptc-go alive for years to come, or want users to migrate now. I guess that's up to you to decide, if you want to maintain both ptc-go and ptb 😊

@martinhpedersen

Copy link
Copy Markdown
Member

I've fixed the build failure @ develop. A rebase of your branch should resolve the build check.

@harenber

Copy link
Copy Markdown
Contributor Author

Thanks for the review Martin,

I addressed both items, implemented pactor+ptb and pactor+serial as you suggested. On the long run, on can probably discontinue the old approach, but as people are actively using it, I'd leave it in for the time being. Furthermore it doesn't need an additional program to run, which might be helpful for some ops out there.

Connection tests succeeded:

cubietruck:~$ cd /tmp
cubietruck:/tmp$ PAT_DEBUG=1 ./pat connect pactor+ptb:///DL0XR
2026/07/25 14:44:37 [DEBUG] Version: v1.0.0 (9745dfa) linux/amd64 - go1.26.5
2026/07/25 14:44:37 [DEBUG] Command: connect [pactor+ptb:///DL0XR]
2026/07/25 14:44:37 [DEBUG] Mailbox dir is	'/home/harenber/.local/share/pat/mailbox'
2026/07/25 14:44:37 [DEBUG] Forms dir is	'/home/harenber/.local/share/pat/Standard_Forms'
2026/07/25 14:44:37 [DEBUG] Config file is	'/home/harenber/.config/pat/config.json'
2026/07/25 14:44:37 [DEBUG] Log file is 	'/home/harenber/.local/state/pat/pat.log'
2026/07/25 14:44:37 [DEBUG] Event log file is	'/home/harenber/.local/state/pat/eventlog.json'
2026/07/25 14:44:37 [DEBUG] new config directory /home/harenber/.config/pat already exists, we have already migrated
2026/07/25 14:44:37 [DEBUG] Failed to initialize VOACAP: failed to find executable: exec: "voacapl": executable file not found in $PATH
2026/07/25 14:44:37 [DEBUG] Checking for active Winlink account...
2026/07/25 14:44:37 [DEBUG] Skipping "account-confirmed" (last run: 386h35m0s ago)
2026/07/25 14:44:37 [DEBUG] Account confirmation error: call was rate-limited
2026/07/25 14:44:37 [DEBUG] connectStr: pactor+ptb:///DL0XR
2026/07/25 14:44:37 [DEBUG] Skipping "version_report" (last run: 3m0s ago)
2026/07/25 14:44:37 [DEBUG] Skipping "pw_recovery_email_check" (last run: 3m0s ago)
2026/07/25 14:44:37 PTB TX CMD: I DL1THM
2026/07/25 14:44:37 PTB modem initialized at localhost:8300 (data: localhost:8301)
2026/07/25 14:44:37 Connecting to DL0XR (pactor+ptb)...
2026/07/25 14:44:37 PTB TX CMD: C DL0XR
2026/07/25 14:44:38 PTB RX CMD: 4) CONNECTED to DL0XR
2026/07/25 14:44:38 Connected to ptb:DL0XR (ptb)
Open source Winlink client - getpat.io
;FW: DL0XR
[Pat-1.0.0-B2FHMG$]
; PTB:DL1THM DE DL0XR ()>
GZIP_EXPERIMENT: Gzip compression enabled in this session.
>FF
FQ
2026/07/25 14:44:49 PTB Disconnect requested.
2026/07/25 14:44:53 PTB TX CMD: D
2026/07/25 14:44:55 PTB RX CMD: 4) DISCONNECTED fm DL0XR
2026/07/25 14:44:55 Disconnected.
2026/07/25 14:44:55 [DEBUG] Starting cleanup
2026/07/25 14:44:55 [DEBUG] Closing active connection and/or listeners
2026/07/25 14:44:55 [DEBUG] Closing modems
2026/07/25 14:44:55 [DEBUG] Closing rigs
2026/07/25 14:44:55 [DEBUG] Cleanup done
cubietruck:/tmp$

and

cubietruck:/tmp$ ./pat --listen pactor+ptb --config $HOME/.config/pat/config-dl0xr.json interactive
2026/07/25 14:44:06 Listening for incoming traffic on pactor+ptb...
L[pactor+ptb]> 2026/07/25 14:44:06 PTB TX CMD: I DL0XR
2026/07/25 14:44:06 PTB modem initialized at localhost:8302 (data: localhost:8303)
2026/07/25 14:44:06 PTB TX CMD: %L 1
2026/07/25 14:44:39 PTB RX CMD: 4) CONNECTED to DL1THM
2026/07/25 14:44:39 Got connect (pactor+ptb:ptb:DL1THM)
2026/07/25 14:44:39 Connected to ptb:DL1THM (ptb)
;FW: DL1THM
[Pat-1.0.0-B2FHMG$]
; DL0XR DE DL1THM ()
GZIP_EXPERIMENT: Gzip compression enabled in this session.
FF
>FQ
2026/07/25 14:44:45 PTB Disconnect requested.
2026/07/25 14:44:49 PTB TX CMD: D
2026/07/25 14:44:54 PTB RX CMD: 4) DISCONNECTED fm DL1THM
2026/07/25 14:44:54 Disconnected.

L[pactor+ptb]> q
cubietruck:/tmp$

73s, Torsten

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants