#pragma once #include #using #using #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^ bytes = Encoding::UTF8->GetBytes(msg); try { _ws->SendAsync(ArraySegment(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^ buf = gcnew array(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(buf), System::Net::WebSockets::WebSocketMessageType::Binary, true, System::Threading::CancellationToken::None)->Wait(); } void TxLoop(System::Object^ param) { Drone^ d = safe_cast(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; // признак «живого» цикла };