Files
ETTerms/src/ETTerms/Sessions/SerialChannel.cs
T
etwenandClaude Fable 5 98fbd310d2 feat: v0.5.0 terminal search, keyword alerts, TeraTerm-compatible TTL
Search (Ctrl+F):
- in-terminal search bar over full scrollback + screen; all hits
  highlighted, current hit emphasized; Enter searches upward,
  Shift+Enter downward, F3/Esc shortcuts
- hits anchored via ScreenBuffer.DroppedLines so positions stay
  correct as the ring buffer drops old lines

Keyword highlighting & tab alerts:
- new Settings -> Highlight page: user-defined keyword list with
  per-rule enable and a global toggle (AppSettings.KeywordRules)
- keywords highlighted red in every terminal (visible rows only,
  case-insensitive); background tabs flash a red dot when a keyword
  appears, cleared when the tab is opened

TTL engine (TeraTerm macro compatibility):
- new TtlExpression parser: parens, and/or/xor/not, comparisons,
  * / % + -, hex literals (0x/$), string/int values; legacy fallback
  keeps old scripts working
- control flow: goto, call/return (inline, usable inside loops),
  for/next, do/loop [while|until], until/enduntil, break, continue,
  end, exit, include, mpause; one-line "if <expr> <statement>"
- waits: waitln, waitregex (matchstr/groupmatchstr1-9), recvln,
  multi-string wait (TeraTerm semantics), mtimeout
- strings: strlen strcompare strconcat strcopy strinsert strremove
  strmatch strscan strreplace strtrim strsplit strjoin tolower
  toupper str2int int2str code2str str2code sprintf expandenv
- files: fileopen filereadln filewrite(ln) fileclose filecreate
  filedelete filesearch basename dirname makepath foldercreate
  folderdelete foldersearch getdir setdir
- misc: beep getdate gettime getenv setenv random exec getver
  getttdir uptime ifdefined clipb2var var2clipb inputbox yesnobox
  crc32 checksum8/16/32 dispstr
- serial: sendbreak setbaud setdtr setrts sendfile (SerialChannel
  gains SendBreak/SetBaudRate/SetDtr/SetRts)
- script Output (incl. dispstr) now echoed gray into the terminal
- quote-aware comment stripping; case-insensitive variables

Docs:
- docs/ttl-script-reference.md rewritten: ETTerms-only commands
  first, then the TeraTerm-shared set, with examples

Misc:
- version 0.5.0; About changelog; CLAUDE.md v0.5.0 notes
- restore ETTerms.PduCore ProjectReference in ETTerms/PduMcp csproj
  (was dropped in the working tree; required to compile)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 14:47:06 +08:00

109 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.IO.Ports;
using ETTerms.Connections;
using ETTerms.Infrastructure;
namespace ETTerms.Sessions;
/// <summary>
/// Serial 連線通道:包 <see cref="SerialPort"/>。開啟前向 SessionManager 占用 COM port(互斥)。
/// </summary>
public sealed class SerialChannel : ISessionChannel
{
private readonly SerialPort _port;
private readonly string _portName;
private bool _opened;
public event Action<byte[]>? DataReceived;
public string LogName => _portName;
/// <summary>目前傳輸速率(供 MCP 橋接列出 session 用)。</summary>
public int BaudRate => _port.BaudRate;
/// <summary>送出換行序列(AI 寫入時附加,與手打 Enter 一致)。</summary>
public string NewLine => _port.NewLine;
public SerialChannel(SerialSettings s)
{
_portName = s.PortName;
_port = new SerialPort(s.PortName, s.BaudRate, s.Parity, s.DataBits, s.StopBits)
{
Handshake = s.Handshake,
NewLine = s.NewLine
};
_port.DataReceived += OnData;
}
public void Open()
{
if (!SessionManager.TryReservePort(_portName))
throw new InvalidOperationException($"COM port {_portName} is already in use by another session.");
try
{
_port.Open();
_opened = true;
AppLogger.Info($"Serial opened: {_portName} @ {_port.BaudRate}");
}
catch
{
SessionManager.ReleasePort(_portName);
throw;
}
}
private void OnData(object sender, SerialDataReceivedEventArgs e)
{
try
{
int n = _port.BytesToRead;
if (n <= 0) return;
var buf = new byte[n];
int read = _port.Read(buf, 0, n);
if (read > 0) DataReceived?.Invoke(read == n ? buf : buf[..read]);
}
catch (Exception ex)
{
AppLogger.LogWarning($"Serial read error on {_portName}: {ex.Message}");
}
}
public void Write(byte[] data)
{
if (_port.IsOpen) _port.Write(data, 0, data.Length);
}
// ── TTL serial 控制指令用(sendbreak / setbaud / setdtr / setrts)──
/// <summary>送出 serial break(拉 break 狀態約 300ms)。</summary>
public void SendBreak()
{
if (!_port.IsOpen) return;
try { _port.BreakState = true; Thread.Sleep(300); }
finally { try { _port.BreakState = false; } catch { } }
}
/// <summary>執行中變更 baud rateTTL setbaud)。</summary>
public void SetBaudRate(int baud) => _port.BaudRate = baud;
public void SetDtr(bool on) => _port.DtrEnable = on;
public void SetRts(bool on) => _port.RtsEnable = on;
public void Resize(int cols, int rows) { /* serial 無 PTY size */ }
public void Close()
{
if (!_opened) return;
_opened = false;
try { if (_port.IsOpen) _port.Close(); } catch { /* 忽略關閉錯誤 */ }
SessionManager.ReleasePort(_portName);
AppLogger.Info($"Serial closed: {_portName}");
}
public void Dispose()
{
_port.DataReceived -= OnData;
Close();
_port.Dispose();
}
}