mirror of https://github.com/jetkvm/kvm.git
Update serial console part
This commit is contained in:
parent
7c09ac3c08
commit
0630a7bcb1
64
serial.go
64
serial.go
|
|
@ -255,20 +255,9 @@ func setDCRestoreState(state int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mountSerialButtons() error {
|
|
||||||
_ = port.SetMode(defaultMode)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmountSerialButtons() error {
|
|
||||||
_ = reopenSerialPort()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendCustomCommand(command string) error {
|
func sendCustomCommand(command string) error {
|
||||||
scopedLogger := serialLogger.With().Str("service", "custom_buttons_tx").Logger()
|
scopedLogger := serialLogger.With().Str("service", "custom_buttons_tx").Logger()
|
||||||
scopedLogger.Info().Str("Command", command).Msg("Sending custom command.")
|
scopedLogger.Debug().Msgf("Sending custom command: %q", command)
|
||||||
scopedLogger.Info().Msgf("Sending custom command: %q", command)
|
|
||||||
if serialMux == nil {
|
if serialMux == nil {
|
||||||
return fmt.Errorf("serial mux not initialized")
|
return fmt.Errorf("serial mux not initialized")
|
||||||
}
|
}
|
||||||
|
|
@ -325,7 +314,7 @@ type SerialSettings struct {
|
||||||
HideSerialSettings bool `json:"hideSerialSettings"` // Whether to hide the serial settings in the UI
|
HideSerialSettings bool `json:"hideSerialSettings"` // Whether to hide the serial settings in the UI
|
||||||
EnableEcho bool `json:"enableEcho"` // Whether to echo received characters back to the sender
|
EnableEcho bool `json:"enableEcho"` // Whether to echo received characters back to the sender
|
||||||
NormalizeMode string `json:"normalizeMode"` // Normalization mode: "carret", "names", "hex"
|
NormalizeMode string `json:"normalizeMode"` // Normalization mode: "carret", "names", "hex"
|
||||||
NormalizeLineEnd string `json:"normalizeLineEnd"` // Line ending normalization: "keep", "lf", "cr", "crlf"
|
NormalizeLineEnd string `json:"normalizeLineEnd"` // Line ending normalization: "keep", "lf", "cr", "crlf", "lfcr"
|
||||||
TabRender string `json:"tabRender"` // How to render tabs: "spaces", "arrow", "pipe"
|
TabRender string `json:"tabRender"` // How to render tabs: "spaces", "arrow", "pipe"
|
||||||
PreserveANSI bool `json:"preserveANSI"` // Whether to preserve ANSI escape codes
|
PreserveANSI bool `json:"preserveANSI"` // Whether to preserve ANSI escape codes
|
||||||
ShowNLTag bool `json:"showNLTag"` // Whether to show a special tag for new lines
|
ShowNLTag bool `json:"showNLTag"` // Whether to show a special tag for new lines
|
||||||
|
|
@ -358,7 +347,7 @@ func getSerialSettings() (SerialSettings, error) {
|
||||||
|
|
||||||
file, err := os.Open(serialSettingsPath)
|
file, err := os.Open(serialSettingsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debug().Msg("SerialButtons config file doesn't exist, using default")
|
logger.Info().Msg("SerialButtons config file doesn't exist, using default")
|
||||||
return serialConfig, err
|
return serialConfig, err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
@ -412,7 +401,7 @@ func getSerialSettings() (SerialSettings, error) {
|
||||||
|
|
||||||
var normalizeMode NormalizeMode
|
var normalizeMode NormalizeMode
|
||||||
switch serialConfig.NormalizeMode {
|
switch serialConfig.NormalizeMode {
|
||||||
case "carret":
|
case "caret":
|
||||||
normalizeMode = ModeCaret
|
normalizeMode = ModeCaret
|
||||||
case "names":
|
case "names":
|
||||||
normalizeMode = ModeNames
|
normalizeMode = ModeNames
|
||||||
|
|
@ -422,25 +411,25 @@ func getSerialSettings() (SerialSettings, error) {
|
||||||
normalizeMode = ModeNames
|
normalizeMode = ModeNames
|
||||||
}
|
}
|
||||||
|
|
||||||
var crlfMode CRLFMode
|
var crlfMode LineEndingMode
|
||||||
switch serialConfig.NormalizeLineEnd {
|
switch serialConfig.NormalizeLineEnd {
|
||||||
case "keep":
|
case "keep":
|
||||||
crlfMode = CRLFAsIs
|
crlfMode = LineEnding_AsIs
|
||||||
case "lf":
|
case "lf":
|
||||||
crlfMode = CRLF_LF
|
crlfMode = LineEnding_LF
|
||||||
case "cr":
|
case "cr":
|
||||||
crlfMode = CRLF_CR
|
crlfMode = LineEnding_CR
|
||||||
case "crlf":
|
case "crlf":
|
||||||
crlfMode = CRLF_CRLF
|
crlfMode = LineEnding_CRLF
|
||||||
case "lfcr":
|
case "lfcr":
|
||||||
crlfMode = CRLF_LFCR
|
crlfMode = LineEnding_LFCR
|
||||||
default:
|
default:
|
||||||
crlfMode = CRLFAsIs
|
crlfMode = LineEnding_AsIs
|
||||||
}
|
}
|
||||||
|
|
||||||
if consoleBroker != nil {
|
if consoleBroker != nil {
|
||||||
norm := NormOptions{
|
norm := NormalizationOptions{
|
||||||
Mode: normalizeMode, CRLF: crlfMode, TabRender: serialConfig.TabRender, PreserveANSI: serialConfig.PreserveANSI, ShowNLTag: serialConfig.ShowNLTag,
|
Mode: normalizeMode, LineEnding: crlfMode, TabRender: serialConfig.TabRender, PreserveANSI: serialConfig.PreserveANSI, ShowNLTag: serialConfig.ShowNLTag,
|
||||||
}
|
}
|
||||||
consoleBroker.SetNormOptions(norm)
|
consoleBroker.SetNormOptions(norm)
|
||||||
}
|
}
|
||||||
|
|
@ -507,7 +496,7 @@ func setSerialSettings(newSettings SerialSettings) error {
|
||||||
|
|
||||||
var normalizeMode NormalizeMode
|
var normalizeMode NormalizeMode
|
||||||
switch serialConfig.NormalizeMode {
|
switch serialConfig.NormalizeMode {
|
||||||
case "carret":
|
case "caret":
|
||||||
normalizeMode = ModeCaret
|
normalizeMode = ModeCaret
|
||||||
case "names":
|
case "names":
|
||||||
normalizeMode = ModeNames
|
normalizeMode = ModeNames
|
||||||
|
|
@ -517,25 +506,25 @@ func setSerialSettings(newSettings SerialSettings) error {
|
||||||
normalizeMode = ModeNames
|
normalizeMode = ModeNames
|
||||||
}
|
}
|
||||||
|
|
||||||
var crlfMode CRLFMode
|
var crlfMode LineEndingMode
|
||||||
switch serialConfig.NormalizeLineEnd {
|
switch serialConfig.NormalizeLineEnd {
|
||||||
case "keep":
|
case "keep":
|
||||||
crlfMode = CRLFAsIs
|
crlfMode = LineEnding_AsIs
|
||||||
case "lf":
|
case "lf":
|
||||||
crlfMode = CRLF_LF
|
crlfMode = LineEnding_LF
|
||||||
case "cr":
|
case "cr":
|
||||||
crlfMode = CRLF_CR
|
crlfMode = LineEnding_CR
|
||||||
case "crlf":
|
case "crlf":
|
||||||
crlfMode = CRLF_CRLF
|
crlfMode = LineEnding_CRLF
|
||||||
case "lfcr":
|
case "lfcr":
|
||||||
crlfMode = CRLF_LFCR
|
crlfMode = LineEnding_LFCR
|
||||||
default:
|
default:
|
||||||
crlfMode = CRLFAsIs
|
crlfMode = LineEnding_AsIs
|
||||||
}
|
}
|
||||||
|
|
||||||
if consoleBroker != nil {
|
if consoleBroker != nil {
|
||||||
norm := NormOptions{
|
norm := NormalizationOptions{
|
||||||
Mode: normalizeMode, CRLF: crlfMode, TabRender: serialConfig.TabRender, PreserveANSI: serialConfig.PreserveANSI, ShowNLTag: serialConfig.ShowNLTag,
|
Mode: normalizeMode, LineEnding: crlfMode, TabRender: serialConfig.TabRender, PreserveANSI: serialConfig.PreserveANSI, ShowNLTag: serialConfig.ShowNLTag,
|
||||||
}
|
}
|
||||||
consoleBroker.SetNormOptions(norm)
|
consoleBroker.SetNormOptions(norm)
|
||||||
}
|
}
|
||||||
|
|
@ -575,8 +564,8 @@ func reopenSerialPort() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// new broker (no sink yet—set it in handleSerialChannel.OnOpen)
|
// new broker (no sink yet—set it in handleSerialChannel.OnOpen)
|
||||||
norm := NormOptions{
|
norm := NormalizationOptions{
|
||||||
Mode: ModeNames, CRLF: CRLF_LF, TabRender: "", PreserveANSI: true,
|
Mode: ModeNames, LineEnding: LineEnding_LF, TabRender: "", PreserveANSI: true,
|
||||||
}
|
}
|
||||||
if consoleBroker != nil {
|
if consoleBroker != nil {
|
||||||
consoleBroker.Close()
|
consoleBroker.Close()
|
||||||
|
|
@ -612,8 +601,7 @@ func handleSerialChannel(dataChannel *webrtc.DataChannel) {
|
||||||
|
|
||||||
dataChannel.OnMessage(func(msg webrtc.DataChannelMessage) {
|
dataChannel.OnMessage(func(msg webrtc.DataChannelMessage) {
|
||||||
|
|
||||||
scopedLogger.Info().Bytes("Data:", msg.Data).Msg("Sending data to serial mux")
|
scopedLogger.Trace().Bytes("Data:", msg.Data).Msg("Sending data to serial mux")
|
||||||
scopedLogger.Info().Msgf("Sending data to serial mux: %q", msg.Data)
|
|
||||||
if serialMux == nil {
|
if serialMux == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,25 +31,25 @@ const (
|
||||||
ModeHex // \x1B
|
ModeHex // \x1B
|
||||||
)
|
)
|
||||||
|
|
||||||
type CRLFMode int
|
type LineEndingMode int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CRLFAsIs CRLFMode = iota
|
LineEnding_AsIs LineEndingMode = iota
|
||||||
CRLF_LF
|
LineEnding_LF
|
||||||
CRLF_CR
|
LineEnding_CR
|
||||||
CRLF_CRLF
|
LineEnding_CRLF
|
||||||
CRLF_LFCR
|
LineEnding_LFCR
|
||||||
)
|
)
|
||||||
|
|
||||||
type NormOptions struct {
|
type NormalizationOptions struct {
|
||||||
Mode NormalizeMode
|
Mode NormalizeMode
|
||||||
CRLF CRLFMode
|
LineEnding LineEndingMode
|
||||||
TabRender string // e.g. " " or "" to keep '\t'
|
TabRender string // e.g. " " or "" to keep '\t'
|
||||||
PreserveANSI bool
|
PreserveANSI bool
|
||||||
ShowNLTag bool // <- NEW: also print a visible tag for CR/LF
|
ShowNLTag bool // print a visible tag for CR/LF like <CR>, <LF>, <CRLF>
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalize(in []byte, opt NormOptions) string {
|
func normalize(in []byte, opt NormalizationOptions) string {
|
||||||
var out strings.Builder
|
var out strings.Builder
|
||||||
esc := byte(0x1B)
|
esc := byte(0x1B)
|
||||||
for i := 0; i < len(in); {
|
for i := 0; i < len(in); {
|
||||||
|
|
@ -113,8 +113,8 @@ func normalize(in []byte, opt NormOptions) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// now emit the actual newline(s) per the normalization mode
|
// now emit the actual newline(s) per the normalization mode
|
||||||
switch opt.CRLF {
|
switch opt.LineEnding {
|
||||||
case CRLFAsIs:
|
case LineEnding_AsIs:
|
||||||
if isPair {
|
if isPair {
|
||||||
out.WriteByte(b)
|
out.WriteByte(b)
|
||||||
out.WriteByte(in[i+1])
|
out.WriteByte(in[i+1])
|
||||||
|
|
@ -123,28 +123,28 @@ func normalize(in []byte, opt NormOptions) string {
|
||||||
out.WriteByte(b)
|
out.WriteByte(b)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
case CRLF_LF:
|
case LineEnding_LF:
|
||||||
if isPair {
|
if isPair {
|
||||||
i += 2
|
i += 2
|
||||||
} else {
|
} else {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
out.WriteByte('\n')
|
out.WriteByte('\n')
|
||||||
case CRLF_CR:
|
case LineEnding_CR:
|
||||||
if isPair {
|
if isPair {
|
||||||
i += 2
|
i += 2
|
||||||
} else {
|
} else {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
out.WriteByte('\r')
|
out.WriteByte('\r')
|
||||||
case CRLF_CRLF:
|
case LineEnding_CRLF:
|
||||||
if isPair {
|
if isPair {
|
||||||
i += 2
|
i += 2
|
||||||
} else {
|
} else {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
out.WriteString("\r\n") // (fixed to actually write CRLF)
|
out.WriteString("\r\n")
|
||||||
case CRLF_LFCR:
|
case LineEnding_LFCR:
|
||||||
if isPair {
|
if isPair {
|
||||||
i += 2
|
i += 2
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -238,14 +238,14 @@ type ConsoleBroker struct {
|
||||||
quietAfter time.Duration
|
quietAfter time.Duration
|
||||||
|
|
||||||
// normalization
|
// normalization
|
||||||
norm NormOptions
|
norm NormalizationOptions
|
||||||
|
|
||||||
// labels
|
// labels
|
||||||
labelRX string
|
labelRX string
|
||||||
labelTX string
|
labelTX string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConsoleBroker(s Sink, norm NormOptions) *ConsoleBroker {
|
func NewConsoleBroker(s Sink, norm NormalizationOptions) *ConsoleBroker {
|
||||||
return &ConsoleBroker{
|
return &ConsoleBroker{
|
||||||
sink: s,
|
sink: s,
|
||||||
in: make(chan consoleEvent, 256),
|
in: make(chan consoleEvent, 256),
|
||||||
|
|
@ -264,10 +264,10 @@ func NewConsoleBroker(s Sink, norm NormOptions) *ConsoleBroker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ConsoleBroker) Start() { go b.loop() }
|
func (b *ConsoleBroker) Start() { go b.loop() }
|
||||||
func (b *ConsoleBroker) Close() { close(b.done) }
|
func (b *ConsoleBroker) Close() { close(b.done) }
|
||||||
func (b *ConsoleBroker) SetSink(s Sink) { b.sink = s }
|
func (b *ConsoleBroker) SetSink(s Sink) { b.sink = s }
|
||||||
func (b *ConsoleBroker) SetNormOptions(norm NormOptions) { b.norm = norm }
|
func (b *ConsoleBroker) SetNormOptions(norm NormalizationOptions) { b.norm = norm }
|
||||||
func (b *ConsoleBroker) SetTerminalPaused(v bool) {
|
func (b *ConsoleBroker) SetTerminalPaused(v bool) {
|
||||||
if b == nil {
|
if b == nil {
|
||||||
return
|
return
|
||||||
|
|
@ -293,23 +293,23 @@ func (b *ConsoleBroker) loop() {
|
||||||
|
|
||||||
case v := <-b.pauseCh:
|
case v := <-b.pauseCh:
|
||||||
// apply pause state
|
// apply pause state
|
||||||
was := b.terminalPaused
|
wasPaused := b.terminalPaused
|
||||||
b.terminalPaused = v
|
b.terminalPaused = v
|
||||||
if was && !v {
|
if wasPaused && !v {
|
||||||
// we just unpaused: flush buffered output in order
|
// we just unpaused: flush buffered output in order
|
||||||
scopedLogger.Info().Msg("Terminal unpaused; flushing buffered output")
|
scopedLogger.Trace().Msg("Terminal unpaused; flushing buffered output")
|
||||||
b.flushBuffer()
|
b.flushBuffer()
|
||||||
} else if !was && v {
|
} else if !wasPaused && v {
|
||||||
scopedLogger.Info().Msg("Terminal paused; buffering output")
|
scopedLogger.Trace().Msg("Terminal paused; buffering output")
|
||||||
}
|
}
|
||||||
|
|
||||||
case ev := <-b.in:
|
case ev := <-b.in:
|
||||||
switch ev.kind {
|
switch ev.kind {
|
||||||
case evRX:
|
case evRX:
|
||||||
scopedLogger.Info().Msg("Processing RX data from serial port")
|
scopedLogger.Trace().Msg("Processing RX data from serial port")
|
||||||
b.handleRX(ev.data)
|
b.handleRX(ev.data)
|
||||||
case evTX:
|
case evTX:
|
||||||
scopedLogger.Info().Msg("Processing TX echo request")
|
scopedLogger.Trace().Msg("Processing TX echo request")
|
||||||
b.handleTX(ev.data)
|
b.handleTX(ev.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -367,10 +367,10 @@ func (b *ConsoleBroker) handleRX(data []byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scopedLogger.Info().Msg("Emitting RX data to sink (with per-line prefixes)")
|
scopedLogger.Trace().Msg("Emitting RX data to sink (with per-line prefixes)")
|
||||||
|
|
||||||
// Prefix every line, regardless of how the EOLs look
|
// Prefix every line, regardless of how the EOLs look
|
||||||
lines := splitAfterAnyEOL(text, b.norm.CRLF)
|
lines := splitAfterAnyEOL(text, b.norm.LineEnding)
|
||||||
|
|
||||||
// Start from the broker's current RX line state
|
// Start from the broker's current RX line state
|
||||||
atLineEnd := b.rxAtLineEnd
|
atLineEnd := b.rxAtLineEnd
|
||||||
|
|
@ -389,7 +389,7 @@ func (b *ConsoleBroker) handleRX(data []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update line-end state based on this piece
|
// Update line-end state based on this piece
|
||||||
atLineEnd = endsWithEOL(line, b.norm.CRLF)
|
atLineEnd = endsWithEOL(line, b.norm.LineEnding)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist state for next RX chunk
|
// Persist state for next RX chunk
|
||||||
|
|
@ -407,11 +407,11 @@ func (b *ConsoleBroker) handleTX(data []byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if b.rxAtLineEnd && b.pendingTX == nil {
|
if b.rxAtLineEnd && b.pendingTX == nil {
|
||||||
scopedLogger.Info().Msg("Emitting TX data to sink immediately")
|
scopedLogger.Trace().Msg("Emitting TX data to sink immediately")
|
||||||
b.emitTX(data)
|
b.emitTX(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
scopedLogger.Info().Msg("Queuing TX data to emit after RX line completion or quiet period")
|
scopedLogger.Trace().Msg("Queuing TX data to emit after RX line completion or quiet period")
|
||||||
b.pendingTX = &consoleEvent{kind: evTX, data: append([]byte(nil), data...)}
|
b.pendingTX = &consoleEvent{kind: evTX, data: append([]byte(nil), data...)}
|
||||||
b.startQuietTimer()
|
b.startQuietTimer()
|
||||||
}
|
}
|
||||||
|
|
@ -430,12 +430,12 @@ func (b *ConsoleBroker) emitTX(data []byte) {
|
||||||
// Check if we’re in the middle of a TX line
|
// Check if we’re in the middle of a TX line
|
||||||
if !b.txLineActive {
|
if !b.txLineActive {
|
||||||
// Start new TX line with prefix
|
// Start new TX line with prefix
|
||||||
scopedLogger.Info().Msg("Emitting TX data to sink with prefix")
|
scopedLogger.Trace().Msg("Emitting TX data to sink with prefix")
|
||||||
b.emitToTerminal(fmt.Sprintf("%s: %s", b.labelTX, text))
|
b.emitToTerminal(fmt.Sprintf("%s: %s", b.labelTX, text))
|
||||||
b.txLineActive = true
|
b.txLineActive = true
|
||||||
} else {
|
} else {
|
||||||
// Continue current line (no prefix)
|
// Continue current line (no prefix)
|
||||||
scopedLogger.Info().Msg("Emitting TX data to sink without prefix")
|
scopedLogger.Trace().Msg("Emitting TX data to sink without prefix")
|
||||||
b.emitToTerminal(text)
|
b.emitToTerminal(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -455,14 +455,14 @@ func (b *ConsoleBroker) flushPendingTX() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ConsoleBroker) lineSep() string {
|
func (b *ConsoleBroker) lineSep() string {
|
||||||
switch b.norm.CRLF {
|
switch b.norm.LineEnding {
|
||||||
case CRLF_CRLF:
|
case LineEnding_CRLF:
|
||||||
return "\r\n"
|
return "\r\n"
|
||||||
case CRLF_LFCR:
|
case LineEnding_LFCR:
|
||||||
return "\n\r"
|
return "\n\r"
|
||||||
case CRLF_CR:
|
case LineEnding_CR:
|
||||||
return "\r"
|
return "\r"
|
||||||
case CRLF_LF:
|
case LineEnding_LF:
|
||||||
return "\n"
|
return "\n"
|
||||||
default:
|
default:
|
||||||
return "\n"
|
return "\n"
|
||||||
|
|
@ -470,26 +470,26 @@ func (b *ConsoleBroker) lineSep() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitAfterAnyEOL splits text into lines keeping the EOL with each piece.
|
// splitAfterAnyEOL splits text into lines keeping the EOL with each piece.
|
||||||
// For CRLFAsIs it treats \r, \n, \r\n, and \n\r as EOLs.
|
// For LineEnding_AsIs it treats \r, \n, \r\n, and \n\r as EOLs.
|
||||||
// For other modes it uses the normalized separator.
|
// For other modes it uses the normalized separator.
|
||||||
func splitAfterAnyEOL(text string, mode CRLFMode) []string {
|
func splitAfterAnyEOL(text string, mode LineEndingMode) []string {
|
||||||
if text == "" {
|
if text == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast path for normalized modes
|
// Fast path for normalized modes
|
||||||
switch mode {
|
switch mode {
|
||||||
case CRLF_LF:
|
case LineEnding_LF:
|
||||||
return strings.SplitAfter(text, "\n")
|
return strings.SplitAfter(text, "\n")
|
||||||
case CRLF_CR:
|
case LineEnding_CR:
|
||||||
return strings.SplitAfter(text, "\r")
|
return strings.SplitAfter(text, "\r")
|
||||||
case CRLF_CRLF:
|
case LineEnding_CRLF:
|
||||||
return strings.SplitAfter(text, "\r\n")
|
return strings.SplitAfter(text, "\r\n")
|
||||||
case CRLF_LFCR:
|
case LineEnding_LFCR:
|
||||||
return strings.SplitAfter(text, "\n\r")
|
return strings.SplitAfter(text, "\n\r")
|
||||||
}
|
}
|
||||||
|
|
||||||
// CRLFAsIs: scan bytes and treat \r, \n, \r\n, \n\r as one boundary
|
// LineEnding_AsIs: scan bytes and treat \r, \n, \r\n, \n\r as one boundary
|
||||||
b := []byte(text)
|
b := []byte(text)
|
||||||
var parts []string
|
var parts []string
|
||||||
start := 0
|
start := 0
|
||||||
|
|
@ -511,18 +511,18 @@ func splitAfterAnyEOL(text string, mode CRLFMode) []string {
|
||||||
return parts
|
return parts
|
||||||
}
|
}
|
||||||
|
|
||||||
func endsWithEOL(s string, mode CRLFMode) bool {
|
func endsWithEOL(s string, mode LineEndingMode) bool {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
switch mode {
|
switch mode {
|
||||||
case CRLF_CRLF:
|
case LineEnding_CRLF:
|
||||||
return strings.HasSuffix(s, "\r\n")
|
return strings.HasSuffix(s, "\r\n")
|
||||||
case CRLF_LFCR:
|
case LineEnding_LFCR:
|
||||||
return strings.HasSuffix(s, "\n\r")
|
return strings.HasSuffix(s, "\n\r")
|
||||||
case CRLF_LF:
|
case LineEnding_LF:
|
||||||
return strings.HasSuffix(s, "\n")
|
return strings.HasSuffix(s, "\n")
|
||||||
case CRLF_CR:
|
case LineEnding_CR:
|
||||||
return strings.HasSuffix(s, "\r")
|
return strings.HasSuffix(s, "\r")
|
||||||
default: // AsIs: any of \r, \n, \r\n, \n\r
|
default: // AsIs: any of \r, \n, \r\n, \n\r
|
||||||
return strings.HasSuffix(s, "\r\n") ||
|
return strings.HasSuffix(s, "\r\n") ||
|
||||||
|
|
@ -606,7 +606,7 @@ func (m *SerialMux) Close() { close(m.done) }
|
||||||
func (m *SerialMux) SetEchoEnabled(v bool) { m.echoEnabled.Store(v) }
|
func (m *SerialMux) SetEchoEnabled(v bool) { m.echoEnabled.Store(v) }
|
||||||
|
|
||||||
func (m *SerialMux) Enqueue(payload []byte, source string, requestEcho bool) {
|
func (m *SerialMux) Enqueue(payload []byte, source string, requestEcho bool) {
|
||||||
serialLogger.Info().Str("src", source).Bool("echo", requestEcho).Msg("Enqueuing TX data to serial port")
|
serialLogger.Trace().Str("src", source).Bool("echo", requestEcho).Msg("Enqueuing TX data to serial port")
|
||||||
m.txQ <- txFrame{payload: append([]byte(nil), payload...), source: source, echo: requestEcho}
|
m.txQ <- txFrame{payload: append([]byte(nil), payload...), source: source, echo: requestEcho}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -627,7 +627,7 @@ func (m *SerialMux) reader() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n > 0 && m.broker != nil {
|
if n > 0 && m.broker != nil {
|
||||||
scopedLogger.Info().Msg("Sending RX data to console broker")
|
scopedLogger.Trace().Msg("Sending RX data to console broker")
|
||||||
m.broker.Enqueue(consoleEvent{kind: evRX, data: append([]byte(nil), buf[:n]...)})
|
m.broker.Enqueue(consoleEvent{kind: evRX, data: append([]byte(nil), buf[:n]...)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -641,14 +641,14 @@ func (m *SerialMux) writer() {
|
||||||
case <-m.done:
|
case <-m.done:
|
||||||
return
|
return
|
||||||
case f := <-m.txQ:
|
case f := <-m.txQ:
|
||||||
scopedLogger.Info().Msg("Writing TX data to serial port")
|
scopedLogger.Trace().Msg("Writing TX data to serial port")
|
||||||
if _, err := m.port.Write(f.payload); err != nil {
|
if _, err := m.port.Write(f.payload); err != nil {
|
||||||
scopedLogger.Warn().Err(err).Str("src", f.source).Msg("serial write failed")
|
scopedLogger.Warn().Err(err).Str("src", f.source).Msg("serial write failed")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// echo (if requested AND globally enabled)
|
// echo (if requested AND globally enabled)
|
||||||
if f.echo && m.echoEnabled.Load() && m.broker != nil {
|
if f.echo && m.echoEnabled.Load() && m.broker != nil {
|
||||||
scopedLogger.Info().Msg("Sending TX echo to console broker")
|
scopedLogger.Trace().Msg("Sending TX echo to console broker")
|
||||||
m.broker.Enqueue(consoleEvent{kind: evTX, data: append([]byte(nil), f.payload...)})
|
m.broker.Enqueue(consoleEvent{kind: evTX, data: append([]byte(nil), f.payload...)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue