forked from CPL/Simulator
156 lines
5.2 KiB
C++
156 lines
5.2 KiB
C++
#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; // признак «живого» цикла
|
||
}; |