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

138 lines
4.3 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.

// joypad.h ───────────────────────────────────────────────────────────
#pragma once
#include <iostream>
#include <iomanip>
#include <Windows.h> // <- для AllocConsole
#using <System.dll>
using namespace System;
using namespace System::IO::Ports;
using namespace System::Threading;
/*---------------------------------------------------------------------
Joypad (i-Bus → COM-порт)
---------------------------------------------------------------------*/
public ref class Joypad
{
public:
/* событие е подписывайтесь_ ➜ ничего в форме не вызовется */
delegate void TickHandler(array<UInt16>^ ch);
event TickHandler^ TickEvent;
Joypad()
{
// -------- открываем консоль один раз ----------------------
static bool consoleReady = false;
if (!consoleReady && ::AllocConsole())
{
FILE* fp;
freopen_s(&fp, "CONOUT$", "w", stdout);
std::cout << " CH1 CH2 CH3 CH4 CH5 CH6\n";
consoleReady = true;
}
// ----------------------------------------------------------
_sp = gcnew SerialPort();
_sp->ReadTimeout = 200;
_sp->ReadBufferSize = 256;
}
/* ---------- запуск ------------------------------------------- */
bool Start(String^ port, int baud )
{
if (_run) return true;
try
{
_sp->PortName = port;
_sp->BaudRate = baud;
_sp->Parity = Parity::None;
_sp->DataBits = 8;
_sp->StopBits = StopBits::One;
_sp->Open();
}
catch (Exception^ ex)
{
System::Diagnostics::Debug::WriteLine("Serial error: " + ex->Message);
return false;
}
_run = true;
_thr = gcnew Thread(gcnew ThreadStart(this, &Joypad::RxLoop));
_thr->IsBackground = true;
_thr->Start();
return true;
}
/* ---------- остановка ---------------------------------------- */
void Stop()
{
_run = false;
if (_thr && _thr->IsAlive) _thr->Join();
if (_sp->IsOpen) _sp->Close();
}
property array<UInt16>^ Channels { array<UInt16>^ get() { return _ch; } }
private:
// ----------- поток приёма i-Bus ---------------------------------
void RxLoop()
{
array<Byte>^ buf = gcnew array<Byte>(64);
array<Byte>^ pkt = gcnew array<Byte>(32);
while (_run)
{
int read = 0;
try { read = _sp->Read(buf, 0, buf->Length); }
catch (TimeoutException^) { continue; }
for (int i = 0; i < read; ++i)
{
_fifo[_head++] = buf[i];
if (_head >= _fifo->Length) _head = 0;
if (_fifo[_head] == 0x20 && _fifo[(_head + 1) & 0x7F] == 0x40)
{
for (int j = 0; j < 32; ++j)
pkt[j] = _fifo[(_head + j) & 0x7F];
if (!CheckPkt(pkt)) continue;
ParseChannels(pkt);
// -------- 1) печать в консоль ----------------
std::cout << '\r';
for (int k = 0; k < 6; ++k)
std::cout << std::setw(6) << _ch[k] << ' ';
std::cout << std::flush;
// ---------------------------------------------
// -------- 2) необязательный вызов события ----
TickEvent(_ch); // raise
}
}
}
}
bool CheckPkt(array<Byte>^ p)
{
UInt16 sum = 0; for (int i = 0; i < 30; ++i) sum += p[i];
sum = 0xFFFF - sum;
return sum == (p[30] | p[31] << 8);
}
void ParseChannels(array<Byte>^ p)
{
for (int i = 0; i < 14; ++i)
_ch[i] = (UInt16)(p[2 + i * 2] | p[3 + i * 2] << 8);
}
/* ---------- поля --------------------------------------------- */
SerialPort^ _sp;
Thread^ _thr;
bool _run = false;
array<UInt16>^ _ch = gcnew array<UInt16>(14);
array<Byte>^ _fifo = gcnew array<Byte>(128);
int _head = 0;
};