2025-04-30 12:16:18 +03:00

156 lines
5.2 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

#pragma once
#include <Windows.h>
#using <System.dll>
#using <System.Net.Http.dll>
#pragma pack(push, 1)
struct angles_native { float pitch, roll, yaw; };
#pragma pack(pop)
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Net;
using namespace System::Net::WebSockets;
using namespace System::Threading;
using namespace System::Text;
using namespace DroneClient; // ← поправьте, если у вас другое
public ref class WsServer // имя можно оставить тем же
{
public:
WsServer() : _connected(false) {}
/* ---------- подключение --------------------------------------- */
bool Connect(String^ uri)
{
if (_connected) return true; // уже подключены
_ws = gcnew ClientWebSocket();
_cts = gcnew CancellationTokenSource();
try
{
// 1) запускаем асинхронное соединение
System::Threading::Tasks::Task^ t =
_ws->ConnectAsync(gcnew Uri(uri), _cts->Token);
// 2) ждём завершения
t->Wait(); // здесь AggregateException «обёртывает»
// все реальные ошибки
_connected = true;
}
catch (AggregateException^ ag)
{
// сообщений может быть несколько выводим главное
Exception^ ex = ag->InnerExceptions->Count
? ag->InnerExceptions[0] : ag;
System::String^ msg = ex->Message;
// типовые причины:
// • WebSocketException (ошибка DNS / connection refused / timeout)
// • NotSupportedException (Windows 7: платформа без WebSocketклиента)
// • InvalidOperationException (неверный URI)
// → выводим в Debug и просто возвращаем false
System::Diagnostics::Debug::WriteLine("Connect error: " + msg);
_connected = false;
}
catch (Exception^ ex) // на всякий случай «прочие»
{
System::Diagnostics::Debug::WriteLine("Connect error: " + ex->Message);
_connected = false;
}
return _connected;
}
/* ---------- отключение ---------------------------------------- */
void Disconnect()
{
if (!_connected) return;
try
{
_ws->CloseAsync(WebSocketCloseStatus::NormalClosure,
"bye", CancellationToken::None)->Wait();
}
catch (Exception^) { /* игнор */ }
_ws = nullptr;
_cts = nullptr;
_connected = false;
}
/* ---------- быстрая отправка строки --------------------------- */
bool SendString(String^ msg)
{
if (!_connected) return false;
array<Byte>^ bytes = Encoding::UTF8->GetBytes(msg);
try
{
_ws->SendAsync(ArraySegment<Byte>(bytes),
WebSocketMessageType::Text,
true, CancellationToken::None)->Wait();
return true;
}
catch (Exception^) { return false; }
}
/* ---------- состояние ---------------------------------------- */
property bool IsConnected
{
bool get() { return _connected; }
}
void SendAnglesBinary(float p, float r, float y)
{
angles_native a = { p, r, y };
// безопасно копируем struct → byte[]
array<System::Byte>^ buf = gcnew array<System::Byte>(sizeof(a));
System::Runtime::InteropServices::GCHandle h =
System::Runtime::InteropServices::GCHandle::Alloc(buf,
System::Runtime::InteropServices::GCHandleType::Pinned);
memcpy(h.AddrOfPinnedObject().ToPointer(), &a, sizeof(a));
h.Free();
// шлём как Binary
_ws->SendAsync(System::ArraySegment<Byte>(buf),
System::Net::WebSockets::WebSocketMessageType::Binary,
true, System::Threading::CancellationToken::None)->Wait();
}
void TxLoop(System::Object^ param)
{
Drone^ d = safe_cast<Drone^>(param);
// 20 мс = 50 Гц
const int PERIOD_MS = 20;
// примерные значения, чтобы «шевелились»
float pitch = 0.0f, roll = 0.0f, yaw = 0.0f;
while (_runTx && _connected)
{
float p = System::Threading::Volatile::Read(d->pitch);
float r = System::Threading::Volatile::Read(d->roll);
float y = System::Threading::Volatile::Read(d->yaw);
SendAnglesBinary(p,r, y);
System::Threading::Thread::Sleep(PERIOD_MS);
}
}
private:
ClientWebSocket^ _ws;
CancellationTokenSource^ _cts;
bool _connected;
public:
// --- рядом с тем, где уже лежит wsClient ---
System::Threading::Thread^ _txThread = nullptr; // поток передатчик
bool _runTx = false; // признак «живого» цикла
};