fix(cat): транспорты — короткая запись в TCP и молчаливый отказ serial-порта

CATTcp.SendStr делал один send на ответ. TCP не обязан отдавать весь буфер за
раз, а усечение здесь не ошибка — длинный ответ (IF, ZZEB, список режимов) мог
уехать обрезанным, и молча. Дописываем остаток в цикле.

CATSerial помечал порт активным ДО SerOpen, а открытие шло внутри потока: при
отказе порт навсегда оставался «работающим» в ActiveCount и UI, а причина
нигде не оседала. Открытие переехало в TCATSerialPort.Start и делается
синхронно, так что отказ виден сразу — FActive остаётся False, причина в новом
свойстве LastError. Поток теперь только читает, закрывает владелец в Stop.

Заодно Andromeda-порт назначался по галке в настройках, без оглядки на то,
поднялся ли порт: HasAndromeda рапортовал о панели, которой нет.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 13:13:46 +03:00
co-authored by Claude Opus 5
parent 27a8d1d5cf
commit 20bf3c1f39
2 changed files with 91 additions and 62 deletions
+21 -11
View File
@@ -161,22 +161,32 @@ begin
end;
procedure TCATTcpClientThread.SendStr(const S: string);
// TCP не обязан отдавать весь буфер за один send: длинный ответ (IF, ZZEB,
// список режимов) мог уехать обрезанным — и молча, потому что усечение здесь
// не ошибка. Дописываем остаток, пока он есть.
var
buf: AnsiString;
n: Integer;
buf: AnsiString;
sent, n: Integer;
begin
if FSocket = SOCK_INVALID then Exit;
buf := AnsiString(S);
if Length(buf) = 0 then Exit;
{$IFDEF MSWINDOWS}
n := send(FSocket, buf[1], Length(buf), 0);
if n = SOCKET_ERROR then begin
{$ELSE}
n := fpSend(FSocket, @buf[1], Length(buf), 0);
if n <= 0 then begin
{$ENDIF}
FMarkDelete := True;
Terminate;
sent := 0;
while sent < Length(buf) do
begin
{$IFDEF MSWINDOWS}
n := send(FSocket, buf[sent + 1], Length(buf) - sent, 0);
if n = SOCKET_ERROR then n := -1;
{$ELSE}
n := fpSend(FSocket, @buf[sent + 1], Length(buf) - sent, 0);
{$ENDIF}
if n <= 0 then
begin
FMarkDelete := True;
Terminate;
Exit;
end;
Inc(sent, n);
end;
end;