package cat // "Serial port busy" is a true statement that helps nobody. // // A COM port has exactly one owner, and when a rig's port is refused the owner // is almost always another program on the same desktop — most often OmniRig, // which stays resident once any application has activated it and keeps the port // of the rig configured in it. An operator switching from OmniRig to a native // backend therefore hits this the moment they save: OpsLog is now asking for a // port OmniRig never let go of. The message named none of that. // // It also happens the other way round, and the wording says so rather than // accusing: a digital application (WSJT-X, JTDX, MSHV) configured on the rig's // port directly, rather than through OpsLog's CAT sharing, holds it just as // firmly. import "strings" // busyHint returns a sentence to append to an open error, or "" when the error // is not about the port being taken. // // Deliberately not a wrapped error: this is advice for a human reading a log, // and it must not change how any caller compares the error. func busyHint(port string, err error) string { if err == nil { return "" } msg := strings.ToLower(err.Error()) busy := strings.Contains(msg, "busy") || strings.Contains(msg, "access is denied") || strings.Contains(msg, "denied") || strings.Contains(msg, "in use") if !busy { return "" } return " — another program holds " + port + ". OmniRig is the usual one (it stays running and keeps the port of the rig configured in it, so a native backend can never have it);" + " a digital application pointed straight at the rig instead of at OpsLog's CAT sharing does the same. Close it, then reconnect." }