2019-10-26 09:25:15 -04:00
|
|
|
//
|
|
|
|
// cysfprotocol.cpp
|
|
|
|
// xlxd
|
|
|
|
//
|
|
|
|
// Created by Jean-Luc Deltombe (LX3JL) on 20/05/2018.
|
|
|
|
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
|
|
|
//
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// This file is part of xlxd.
|
|
|
|
//
|
|
|
|
// xlxd is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// xlxd is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "ccrc.h"
|
|
|
|
#include "cysfpayload.h"
|
|
|
|
#include "cysfclient.h"
|
|
|
|
#include "cysfnodedirfile.h"
|
|
|
|
#include "cysfnodedirhttp.h"
|
|
|
|
#include "cysfutils.h"
|
|
|
|
#include "cysfprotocol.h"
|
|
|
|
#include "creflector.h"
|
|
|
|
#include "cgatekeeper.h"
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// constructor
|
|
|
|
CYsfProtocol::CYsfProtocol()
|
|
|
|
{
|
|
|
|
m_seqNo = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// operation
|
|
|
|
|
|
|
|
bool CYsfProtocol::Init(void)
|
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
|
|
|
|
// base class
|
|
|
|
ok = CProtocol::Init();
|
|
|
|
|
|
|
|
// update the reflector callsign
|
|
|
|
m_ReflectorCallsign.PatchCallsign(0, (const uint8 *)"YSF", 3);
|
|
|
|
|
|
|
|
// create our socket
|
|
|
|
ok &= m_Socket.Open(YSF_PORT);
|
|
|
|
if ( !ok )
|
|
|
|
{
|
|
|
|
std::cout << "Error opening socket on port UDP" << YSF_PORT << " on ip " << g_Reflector.GetListenIp() << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// init the wiresx cmd handler
|
|
|
|
ok &= m_WiresxCmdHandler.Init();
|
|
|
|
|
|
|
|
// update time
|
|
|
|
m_LastKeepaliveTime.Now();
|
|
|
|
|
|
|
|
// done
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CYsfProtocol::Close(void)
|
|
|
|
{
|
|
|
|
// base class
|
|
|
|
CProtocol::Close();
|
|
|
|
|
|
|
|
// and close wiresx handler
|
|
|
|
m_WiresxCmdHandler.Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// task
|
|
|
|
|
|
|
|
void CYsfProtocol::Task(void)
|
|
|
|
{
|
|
|
|
CBuffer Buffer;
|
|
|
|
CIp Ip;
|
|
|
|
CCallsign Callsign;
|
|
|
|
CYSFFICH Fich;
|
|
|
|
CDvHeaderPacket *Header;
|
|
|
|
CDvFramePacket *Frames[5];
|
|
|
|
CWiresxCmd WiresxCmd;
|
|
|
|
|
|
|
|
int iWiresxCmd;
|
|
|
|
int iWiresxArg;
|
|
|
|
|
|
|
|
// handle outgoing packets
|
|
|
|
{
|
|
|
|
// any packet to go ?
|
|
|
|
CWiresxPacketQueue *queue = m_WiresxCmdHandler.GetPacketQueue();
|
|
|
|
while ( !queue->empty() )
|
|
|
|
{
|
|
|
|
CWiresxPacket packet = queue->front();
|
|
|
|
queue->pop();
|
|
|
|
m_Socket.Send(packet.GetBuffer(), packet.GetIp());
|
|
|
|
}
|
|
|
|
m_WiresxCmdHandler.ReleasePacketQueue();
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle incoming packets
|
|
|
|
if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 )
|
|
|
|
{
|
|
|
|
// crack the packet
|
|
|
|
if ( IsValidDvPacket(Buffer, &Fich) )
|
|
|
|
{
|
|
|
|
//std::cout << "FN = " << (int)Fich.getFN() << " FT = " << (int)Fich.getFT() << std::endl;
|
|
|
|
if ( IsValidDvFramePacket(Ip, Fich, Buffer, Frames) )
|
|
|
|
{
|
|
|
|
//std::cout << "YSF DV frame" << std::endl;
|
|
|
|
|
|
|
|
// handle it
|
|
|
|
OnDvFramePacketIn(Frames[0], &Ip);
|
|
|
|
OnDvFramePacketIn(Frames[1], &Ip);
|
|
|
|
OnDvFramePacketIn(Frames[2], &Ip);
|
|
|
|
OnDvFramePacketIn(Frames[3], &Ip);
|
|
|
|
OnDvFramePacketIn(Frames[4], &Ip);
|
|
|
|
}
|
|
|
|
else if ( IsValidDvHeaderPacket(Ip, Fich, Buffer, &Header, Frames) )
|
|
|
|
{
|
|
|
|
//std::cout << "YSF DV header:" << std::endl << *Header << std::endl;
|
|
|
|
//std::cout << "YSF DV header:" << std::endl;
|
|
|
|
|
|
|
|
// node linked and callsign muted?
|
|
|
|
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, PROTOCOL_YSF, Header->GetRpt2Module()) )
|
|
|
|
{
|
|
|
|
// handle it
|
|
|
|
OnDvHeaderPacketIn(Header, Ip);
|
|
|
|
//OnDvFramePacketIn(Frames[0], &Ip);
|
|
|
|
//OnDvFramePacketIn(Frames[1], &Ip);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete Header;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( IsValidDvLastFramePacket(Ip, Fich, Buffer, Frames) )
|
|
|
|
{
|
|
|
|
//std::cout << "YSF last DV frame" << std::endl;
|
|
|
|
|
|
|
|
// handle it
|
|
|
|
OnDvFramePacketIn(Frames[0], &Ip);
|
|
|
|
OnDvLastFramePacketIn((CDvLastFramePacket *)Frames[1], &Ip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( IsValidConnectPacket(Buffer, &Callsign) )
|
|
|
|
{
|
|
|
|
//std::cout << "YSF keepalive/connect packet from " << Callsign << " at " << Ip << std::endl;
|
|
|
|
|
|
|
|
// callsign authorized?
|
|
|
|
if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_YSF) )
|
|
|
|
{
|
|
|
|
// acknowledge the request
|
|
|
|
EncodeConnectAckPacket(&Buffer);
|
|
|
|
m_Socket.Send(Buffer, Ip);
|
|
|
|
|
|
|
|
// add client if needed
|
|
|
|
CClients *clients = g_Reflector.GetClients();
|
|
|
|
CClient *client = clients->FindClient(Callsign, Ip, PROTOCOL_YSF);
|
|
|
|
// client already connected ?
|
|
|
|
if ( client == NULL )
|
|
|
|
{
|
|
|
|
std::cout << "YSF connect packet from " << Callsign << " at " << Ip << std::endl;
|
|
|
|
|
|
|
|
// create the client
|
|
|
|
CYsfClient *newclient = new CYsfClient(Callsign, Ip);
|
|
|
|
|
2019-11-17 04:14:56 -05:00
|
|
|
// aautolink, if enabled
|
|
|
|
#if YSF_AUTOLINK_ENABLE
|
|
|
|
newclient->SetReflectorModule(YSF_AUTOLINK_MODULE);
|
|
|
|
#endif
|
|
|
|
|
2019-10-26 09:25:15 -04:00
|
|
|
// and append
|
|
|
|
clients->AddClient(newclient);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
client->Alive();
|
|
|
|
}
|
|
|
|
// and done
|
|
|
|
g_Reflector.ReleaseClients();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( IsValidwirexPacket(Buffer, &Fich, &Callsign, &iWiresxCmd, &iWiresxArg) )
|
|
|
|
{
|
|
|
|
//std::cout << "YSF Wires-x frame" << std::endl;
|
|
|
|
// prepare the cmd object
|
|
|
|
WiresxCmd = CWiresxCmd(Ip, Callsign, iWiresxCmd, iWiresxArg);
|
|
|
|
// and post it to hadler's queue
|
|
|
|
m_WiresxCmdHandler.GetCmdQueue()->push(WiresxCmd);
|
|
|
|
m_WiresxCmdHandler.ReleaseCmdQueue();
|
2020-01-04 05:17:22 -05:00
|
|
|
}
|
|
|
|
else if ( IsValidServerStatusPacket(Buffer) )
|
|
|
|
{
|
|
|
|
std::cout << "YSF server status enquiry from " << Ip << std::endl;
|
|
|
|
// reply
|
|
|
|
EncodeServerStatusPacket(&Buffer);
|
|
|
|
m_Socket.Send(Buffer, Ip);
|
|
|
|
}
|
2019-10-26 09:25:15 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// invalid packet
|
|
|
|
//std::cout << "YSF packet (" << Buffer.size() << ") from " << Callsign << " at " << Ip << std::endl;
|
|
|
|
//Buffer.DebugDump(g_Reflector.m_DebugFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle end of streaming timeout
|
|
|
|
CheckStreamsTimeout();
|
|
|
|
|
|
|
|
// handle queue from reflector
|
|
|
|
HandleQueue();
|
|
|
|
|
|
|
|
// keep client alive
|
|
|
|
if ( m_LastKeepaliveTime.DurationSinceNow() > YSF_KEEPALIVE_PERIOD )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
HandleKeepalives();
|
|
|
|
|
|
|
|
// update time
|
|
|
|
m_LastKeepaliveTime.Now();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// streams helpers
|
|
|
|
|
|
|
|
bool CYsfProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip)
|
|
|
|
{
|
|
|
|
bool newstream = false;
|
|
|
|
|
|
|
|
// find the stream
|
|
|
|
CPacketStream *stream = GetStream(Header->GetStreamId());
|
|
|
|
if ( stream == NULL )
|
|
|
|
{
|
|
|
|
// no stream open yet, open a new one
|
|
|
|
CCallsign via(Header->GetRpt1Callsign());
|
|
|
|
|
|
|
|
// find this client
|
|
|
|
CClient *client = g_Reflector.GetClients()->FindClient(Ip, PROTOCOL_YSF);
|
|
|
|
if ( client != NULL )
|
|
|
|
{
|
|
|
|
// get client callsign
|
|
|
|
via = client->GetCallsign();
|
|
|
|
// get module it's linked to
|
|
|
|
Header->SetRpt2Module(client->GetReflectorModule());
|
|
|
|
|
|
|
|
// and try to open the stream
|
|
|
|
if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL )
|
|
|
|
{
|
|
|
|
// keep the handle
|
|
|
|
m_Streams.push_back(stream);
|
|
|
|
newstream = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// release
|
|
|
|
g_Reflector.ReleaseClients();
|
|
|
|
|
|
|
|
// update last heard
|
|
|
|
if ( g_Reflector.IsValidModule(Header->GetRpt2Module()) )
|
|
|
|
{
|
|
|
|
g_Reflector.GetUsers()->Hearing(Header->GetMyCallsign(), via, Header->GetRpt2Callsign());
|
|
|
|
g_Reflector.ReleaseUsers();
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete header if needed
|
|
|
|
if ( !newstream )
|
|
|
|
{
|
|
|
|
delete Header;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// stream already open
|
|
|
|
// skip packet, but tickle the stream
|
|
|
|
stream->Tickle();
|
|
|
|
// and delete packet
|
|
|
|
delete Header;
|
|
|
|
}
|
|
|
|
|
|
|
|
// done
|
|
|
|
return newstream;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// queue helper
|
|
|
|
|
|
|
|
void CYsfProtocol::HandleQueue(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
m_Queue.Lock();
|
|
|
|
while ( !m_Queue.empty() )
|
|
|
|
{
|
|
|
|
// get the packet
|
|
|
|
CPacket *packet = m_Queue.front();
|
|
|
|
m_Queue.pop();
|
|
|
|
|
|
|
|
// get our sender's id
|
|
|
|
int iModId = g_Reflector.GetModuleIndex(packet->GetModuleId());
|
|
|
|
|
|
|
|
// encode
|
|
|
|
CBuffer buffer;
|
|
|
|
|
|
|
|
// check if it's header
|
|
|
|
if ( packet->IsDvHeader() )
|
|
|
|
{
|
|
|
|
// update local stream cache
|
|
|
|
// this relies on queue feeder setting valid module id
|
|
|
|
m_StreamsCache[iModId].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet);
|
|
|
|
|
|
|
|
// encode it
|
|
|
|
EncodeDvHeaderPacket((const CDvHeaderPacket &)*packet, &buffer);
|
|
|
|
}
|
|
|
|
// check if it's a last frame
|
|
|
|
else if ( packet->IsLastPacket() )
|
|
|
|
{
|
|
|
|
// encode it
|
|
|
|
EncodeDvLastPacket(m_StreamsCache[iModId].m_dvHeader, &buffer);
|
|
|
|
}
|
|
|
|
// otherwise, just a regular DV frame
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// update local stream cache or send triplet when needed
|
|
|
|
uint8 sid = packet->GetYsfPacketSubId();
|
|
|
|
if ( (sid >= 0) && (sid <= 4) )
|
|
|
|
{
|
|
|
|
//std::cout << (int)sid;
|
|
|
|
m_StreamsCache[iModId].m_dvFrames[sid] = CDvFramePacket((const CDvFramePacket &)*packet);
|
|
|
|
if ( sid == 4 )
|
|
|
|
{
|
|
|
|
|
|
|
|
EncodeDvPacket(m_StreamsCache[iModId].m_dvHeader, m_StreamsCache[iModId].m_dvFrames, &buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// send it
|
|
|
|
if ( buffer.size() > 0 )
|
|
|
|
{
|
|
|
|
// and push it to all our clients linked to the module and who are not streaming in
|
|
|
|
CClients *clients = g_Reflector.GetClients();
|
|
|
|
int index = -1;
|
|
|
|
CClient *client = NULL;
|
|
|
|
while ( (client = clients->FindNextClient(PROTOCOL_YSF, &index)) != NULL )
|
|
|
|
{
|
|
|
|
// is this client busy ?
|
|
|
|
if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetModuleId()) )
|
|
|
|
{
|
|
|
|
// no, send the packet
|
|
|
|
m_Socket.Send(buffer, client->GetIp());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_Reflector.ReleaseClients();
|
|
|
|
}
|
|
|
|
|
|
|
|
// done
|
|
|
|
delete packet;
|
|
|
|
}
|
|
|
|
m_Queue.Unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// keepalive helpers
|
|
|
|
|
|
|
|
void CYsfProtocol::HandleKeepalives(void)
|
|
|
|
{
|
|
|
|
// YSF protocol keepalive request is client tasks
|
|
|
|
// here, just check that all clients are still alive
|
|
|
|
// and disconnect them if not
|
|
|
|
|
|
|
|
// iterate on clients
|
|
|
|
CClients *clients = g_Reflector.GetClients();
|
|
|
|
int index = -1;
|
|
|
|
CClient *client = NULL;
|
|
|
|
while ( (client = clients->FindNextClient(PROTOCOL_YSF, &index)) != NULL )
|
|
|
|
{
|
|
|
|
// is this client busy ?
|
|
|
|
if ( client->IsAMaster() )
|
|
|
|
{
|
|
|
|
// yes, just tickle it
|
|
|
|
client->Alive();
|
|
|
|
}
|
|
|
|
// check it's still with us
|
|
|
|
else if ( !client->IsAlive() )
|
|
|
|
{
|
|
|
|
// no, remove it
|
|
|
|
std::cout << "YSF client " << client->GetCallsign() << " keepalive timeout" << std::endl;
|
|
|
|
clients->RemoveClient(client);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
g_Reflector.ReleaseClients();
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// DV packet decoding helpers
|
|
|
|
|
|
|
|
bool CYsfProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsign)
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','P' };
|
|
|
|
|
|
|
|
bool valid = false;
|
|
|
|
if ( (Buffer.size() == 14) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
|
|
|
|
{
|
|
|
|
callsign->SetCallsign(Buffer.data()+4, 8);
|
|
|
|
callsign->SetModule(YSF_MODULE_ID);
|
|
|
|
valid = (callsign->IsValid());
|
|
|
|
}
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CYsfProtocol::IsValidDvPacket(const CBuffer &Buffer, CYSFFICH *Fich)
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','D' };
|
|
|
|
|
|
|
|
bool valid = false;
|
|
|
|
|
|
|
|
if ( (Buffer.size() == 155) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
|
|
|
|
{
|
|
|
|
// decode YSH fich
|
|
|
|
if ( Fich->decode(&(Buffer.data()[40])) )
|
|
|
|
{
|
|
|
|
valid = (Fich->getDT() == YSF_DT_VD_MODE2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CYsfProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CYSFFICH &Fich, const CBuffer &Buffer, CDvHeaderPacket **header, CDvFramePacket **frames)
|
|
|
|
{
|
|
|
|
bool valid = false;
|
|
|
|
*header = NULL;
|
|
|
|
frames[0] = NULL;
|
|
|
|
frames[1] = NULL;
|
|
|
|
|
|
|
|
// DV header ?
|
|
|
|
if ( Fich.getFI() == YSF_FI_HEADER )
|
|
|
|
{
|
|
|
|
// get stream id
|
|
|
|
uint32 uiStreamId = IpToStreamId(Ip);
|
|
|
|
|
|
|
|
// get header data
|
|
|
|
CYSFPayload ysfPayload;
|
|
|
|
if ( ysfPayload.processHeaderData((unsigned char *)&(Buffer.data()[35])) )
|
|
|
|
{
|
|
|
|
// build DVHeader
|
|
|
|
char sz[YSF_CALLSIGN_LENGTH+1];
|
|
|
|
::memcpy(sz, &(Buffer.data()[14]), YSF_CALLSIGN_LENGTH);
|
|
|
|
sz[YSF_CALLSIGN_LENGTH] = 0;
|
|
|
|
CCallsign csMY = CCallsign((const char *)sz);
|
|
|
|
::memcpy(sz, &(Buffer.data()[4]), YSF_CALLSIGN_LENGTH);
|
|
|
|
sz[YSF_CALLSIGN_LENGTH] = 0;
|
|
|
|
CCallsign rpt1 = CCallsign((const char *)sz);
|
|
|
|
rpt1.SetModule(YSF_MODULE_ID);
|
|
|
|
CCallsign rpt2 = m_ReflectorCallsign;
|
|
|
|
// as YSF protocol does not provide a module-tranlatable
|
|
|
|
// destid, set module to none and rely on OnDvHeaderPacketIn()
|
|
|
|
// to later fill it with proper value
|
|
|
|
rpt2.SetModule(' ');
|
|
|
|
|
|
|
|
// and packet
|
|
|
|
*header = new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, uiStreamId, Fich.getFN());
|
|
|
|
}
|
|
|
|
// and 2 DV Frames
|
|
|
|
{
|
|
|
|
uint8 uiAmbe[AMBE_SIZE];
|
|
|
|
::memset(uiAmbe, 0x00, sizeof(uiAmbe));
|
|
|
|
frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0);
|
|
|
|
frames[1] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check validity of packets
|
|
|
|
if ( ((*header) == NULL) || !(*header)->IsValid() ||
|
|
|
|
(frames[0] == NULL) || !(frames[0]->IsValid()) ||
|
|
|
|
(frames[1] == NULL) || !(frames[1]->IsValid()) )
|
|
|
|
|
|
|
|
{
|
|
|
|
delete *header;
|
|
|
|
*header = NULL;
|
|
|
|
delete frames[0];
|
|
|
|
delete frames[1];
|
|
|
|
frames[0] = NULL;
|
|
|
|
frames[1] = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// done
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CYsfProtocol::IsValidDvFramePacket(const CIp &Ip, const CYSFFICH &Fich, const CBuffer &Buffer, CDvFramePacket **frames)
|
|
|
|
{
|
|
|
|
bool valid = false;
|
|
|
|
frames[0] = NULL;
|
|
|
|
frames[1] = NULL;
|
|
|
|
frames[2] = NULL;
|
|
|
|
frames[3] = NULL;
|
|
|
|
frames[4] = NULL;
|
|
|
|
|
|
|
|
// is it DV frame ?
|
|
|
|
if ( Fich.getFI() == YSF_FI_COMMUNICATIONS )
|
|
|
|
{
|
|
|
|
// get stream id
|
|
|
|
uint32 uiStreamId = IpToStreamId(Ip);
|
|
|
|
|
|
|
|
// get DV frames
|
|
|
|
uint8 ambe0[AMBEPLUS_SIZE];
|
|
|
|
uint8 ambe1[AMBEPLUS_SIZE];
|
|
|
|
uint8 ambe2[AMBEPLUS_SIZE];
|
|
|
|
uint8 ambe3[AMBEPLUS_SIZE];
|
|
|
|
uint8 ambe4[AMBEPLUS_SIZE];
|
|
|
|
uint8 *ambes[5] = { ambe0, ambe1, ambe2, ambe3, ambe4 };
|
|
|
|
CYsfUtils::DecodeVD2Vchs((unsigned char *)&(Buffer.data()[35]), ambes);
|
|
|
|
|
|
|
|
// get DV frames
|
|
|
|
uint8 fid = Buffer.data()[34];
|
|
|
|
frames[0] = new CDvFramePacket(ambe0, uiStreamId, Fich.getFN(), 0, fid);
|
|
|
|
frames[1] = new CDvFramePacket(ambe1, uiStreamId, Fich.getFN(), 1, fid);
|
|
|
|
frames[2] = new CDvFramePacket(ambe2, uiStreamId, Fich.getFN(), 2, fid);
|
|
|
|
frames[3] = new CDvFramePacket(ambe3, uiStreamId, Fich.getFN(), 3, fid);
|
|
|
|
frames[4] = new CDvFramePacket(ambe4, uiStreamId, Fich.getFN(), 4, fid);
|
|
|
|
|
|
|
|
// check validity of packets
|
|
|
|
if ( (frames[0] == NULL) || !(frames[0]->IsValid()) ||
|
|
|
|
(frames[1] == NULL) || !(frames[1]->IsValid()) ||
|
|
|
|
(frames[2] == NULL) || !(frames[2]->IsValid()) ||
|
|
|
|
(frames[3] == NULL) || !(frames[3]->IsValid()) ||
|
|
|
|
(frames[4] == NULL) || !(frames[4]->IsValid()) )
|
|
|
|
{
|
|
|
|
delete frames[0];
|
|
|
|
delete frames[1];
|
|
|
|
delete frames[2];
|
|
|
|
delete frames[3];
|
|
|
|
delete frames[4];
|
|
|
|
frames[0] = NULL;
|
|
|
|
frames[1] = NULL;
|
|
|
|
frames[2] = NULL;
|
|
|
|
frames[3] = NULL;
|
|
|
|
frames[4] = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// done
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CYsfProtocol::IsValidDvLastFramePacket(const CIp &Ip, const CYSFFICH &Fich, const CBuffer &Buffer, CDvFramePacket **frames)
|
|
|
|
{
|
|
|
|
bool valid = false;
|
|
|
|
frames[0] = NULL;
|
|
|
|
frames[1] = NULL;
|
|
|
|
|
|
|
|
// DV header ?
|
|
|
|
if ( Fich.getFI() == YSF_FI_TERMINATOR )
|
|
|
|
{
|
|
|
|
// get stream id
|
|
|
|
uint32 uiStreamId = IpToStreamId(Ip);
|
|
|
|
|
|
|
|
// get DV frames
|
|
|
|
{
|
|
|
|
uint8 uiAmbe[AMBE_SIZE];
|
|
|
|
::memset(uiAmbe, 0x00, sizeof(uiAmbe));
|
|
|
|
frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0);
|
|
|
|
frames[1] = new CDvLastFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check validity of packets
|
|
|
|
if ( (frames[0] == NULL) || !(frames[0]->IsValid()) ||
|
|
|
|
(frames[1] == NULL) || !(frames[1]->IsValid()) )
|
|
|
|
|
|
|
|
{
|
|
|
|
delete frames[0];
|
|
|
|
delete frames[1];
|
|
|
|
frames[0] = NULL;
|
|
|
|
frames[1] = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// done
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// DV packet encoding helpers
|
|
|
|
|
|
|
|
void CYsfProtocol::EncodeConnectAckPacket(CBuffer *Buffer) const
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','P','R','E','F','L','E','C','T','O','R',0x20 };
|
|
|
|
|
|
|
|
Buffer->Set(tag, sizeof(tag));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CYsfProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Header, CBuffer *Buffer) const
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','D' };
|
|
|
|
uint8 dest[] = { 'A','L','L',' ',' ',' ',' ',' ',' ',' ' };
|
|
|
|
char sz[YSF_CALLSIGN_LENGTH];
|
|
|
|
uint8 fichd[YSF_FICH_LENGTH_BYTES];
|
|
|
|
|
|
|
|
// tag
|
|
|
|
Buffer->Set(tag, sizeof(tag));
|
|
|
|
// rpt1
|
|
|
|
::memset(sz, ' ', sizeof(sz));
|
|
|
|
Header.GetRpt1Callsign().GetCallsignString(sz);
|
|
|
|
sz[::strlen(sz)] = ' ';
|
|
|
|
Buffer->Append((uint8 *)sz, YSF_CALLSIGN_LENGTH);
|
|
|
|
// my
|
|
|
|
::memset(sz, ' ', sizeof(sz));
|
|
|
|
Header.GetMyCallsign().GetCallsignString(sz);
|
|
|
|
sz[::strlen(sz)] = ' ';
|
|
|
|
Buffer->Append((uint8 *)sz, YSF_CALLSIGN_LENGTH);
|
|
|
|
// dest
|
|
|
|
Buffer->Append(dest, 10);
|
|
|
|
// net frame counter
|
|
|
|
Buffer->Append((uint8)0x00);
|
|
|
|
// FS
|
|
|
|
Buffer->Append((uint8 *)YSF_SYNC_BYTES, YSF_SYNC_LENGTH_BYTES);
|
|
|
|
// FICH
|
|
|
|
CYSFFICH fich;
|
|
|
|
fich.setFI(YSF_FI_HEADER);
|
|
|
|
fich.setCS(2U);
|
|
|
|
//fich.setFN(Header.GetYsfPacketId());
|
|
|
|
fich.setFN(0U);
|
|
|
|
fich.setFT(7U);
|
|
|
|
fich.setDev(0U);
|
|
|
|
fich.setMR(YSF_MR_BUSY);
|
|
|
|
fich.setDT(YSF_DT_VD_MODE2);
|
|
|
|
fich.setSQL(0U);
|
|
|
|
fich.setSQ(0U);
|
|
|
|
fich.encode(fichd);
|
|
|
|
Buffer->Append(fichd, YSF_FICH_LENGTH_BYTES);
|
|
|
|
// payload
|
|
|
|
unsigned char csd1[20U], csd2[20U];
|
|
|
|
::memset(csd1, '*', YSF_CALLSIGN_LENGTH);
|
|
|
|
::memset(csd1 + YSF_CALLSIGN_LENGTH, ' ', YSF_CALLSIGN_LENGTH);
|
|
|
|
Header.GetMyCallsign().GetCallsignString(sz);
|
|
|
|
::memcpy(csd1 + YSF_CALLSIGN_LENGTH, sz, ::strlen(sz));
|
|
|
|
::memset(csd2, ' ', YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH);
|
|
|
|
CYSFPayload payload;
|
|
|
|
uint8 temp[120];
|
|
|
|
payload.writeHeader(temp, csd1, csd2);
|
|
|
|
Buffer->Append(temp+30, 120-30);
|
|
|
|
|
|
|
|
// done
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CYsfProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFramePacket *DvFrames, CBuffer *Buffer) const
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','D' };
|
|
|
|
uint8 dest[] = { 'A','L','L',' ',' ',' ',' ',' ',' ',' ' };
|
|
|
|
uint8 gps[] = { 0x52,0x22,0x61,0x5F,0x27,0x03,0x5E,0x20,0x20,0x20 };
|
|
|
|
char sz[YSF_CALLSIGN_LENGTH];
|
|
|
|
uint8 fichd[YSF_FICH_LENGTH_BYTES];
|
|
|
|
|
|
|
|
// tag
|
|
|
|
Buffer->Set(tag, sizeof(tag));
|
|
|
|
// rpt1
|
|
|
|
::memset(sz, ' ', sizeof(sz));
|
|
|
|
Header.GetRpt1Callsign().GetCallsignString(sz);
|
|
|
|
sz[::strlen(sz)] = ' ';
|
|
|
|
Buffer->Append((uint8 *)sz, YSF_CALLSIGN_LENGTH);
|
|
|
|
// my
|
|
|
|
::memset(sz, ' ', sizeof(sz));
|
|
|
|
Header.GetMyCallsign().GetCallsignString(sz);
|
|
|
|
sz[::strlen(sz)] = ' ';
|
|
|
|
Buffer->Append((uint8 *)sz, YSF_CALLSIGN_LENGTH);
|
|
|
|
// dest
|
|
|
|
Buffer->Append(dest, 10);
|
|
|
|
// net frame counter
|
|
|
|
Buffer->Append(DvFrames[0].GetYsfPacketFrameId());
|
|
|
|
// FS
|
|
|
|
Buffer->Append((uint8 *)YSF_SYNC_BYTES, YSF_SYNC_LENGTH_BYTES);
|
|
|
|
// FICH
|
|
|
|
CYSFFICH fich;
|
|
|
|
fich.setFI(YSF_FI_COMMUNICATIONS);
|
|
|
|
fich.setCS(2U);
|
|
|
|
fich.setFN(DvFrames[0].GetYsfPacketId());
|
|
|
|
fich.setFT(6U);
|
|
|
|
fich.setDev(0U);
|
|
|
|
fich.setMR(YSF_MR_BUSY);
|
|
|
|
fich.setDT(YSF_DT_VD_MODE2);
|
|
|
|
fich.setSQL(0U);
|
|
|
|
fich.setSQ(0U);
|
|
|
|
fich.encode(fichd);
|
|
|
|
Buffer->Append(fichd, YSF_FICH_LENGTH_BYTES);
|
|
|
|
// payload
|
|
|
|
CYSFPayload payload;
|
|
|
|
uint8 temp[120];
|
|
|
|
::memset(temp, 0x00, sizeof(temp));
|
|
|
|
// DV
|
|
|
|
for ( int i = 0; i < 5; i++ )
|
|
|
|
{
|
|
|
|
CYsfUtils::EncodeVD2Vch((unsigned char *)DvFrames[i].GetAmbePlus(), temp+35+(18*i));
|
|
|
|
}
|
|
|
|
// data
|
|
|
|
switch (DvFrames[0].GetYsfPacketId())
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
// Dest
|
|
|
|
payload.writeVDMode2Data(temp, (const unsigned char*)"**********");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
// Src
|
|
|
|
::memset(sz, ' ', sizeof(sz));
|
|
|
|
Header.GetMyCallsign().GetCallsignString(sz);
|
|
|
|
sz[::strlen(sz)] = ' ';
|
|
|
|
payload.writeVDMode2Data(temp, (const unsigned char*)sz);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
// Down
|
|
|
|
::memset(sz, ' ', sizeof(sz));
|
|
|
|
Header.GetRpt1Callsign().GetCallsignString(sz);
|
|
|
|
sz[::strlen(sz)] = ' ';
|
|
|
|
payload.writeVDMode2Data(temp, (const unsigned char*)sz);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
// Rem3+4
|
|
|
|
// we need to provide a fake radioid for radios
|
|
|
|
// to display src callsign
|
|
|
|
payload.writeVDMode2Data(temp, (const unsigned char*)" G0gBJ");
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
// DT1
|
|
|
|
// we need to issue a fake gps string with proper terminator
|
|
|
|
// and crc for radios to display src callsign
|
|
|
|
payload.writeVDMode2Data(temp, gps);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
payload.writeVDMode2Data(temp, (const unsigned char*)" ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
Buffer->Append(temp+30, 120-30);
|
|
|
|
|
|
|
|
// done
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CYsfProtocol::EncodeDvLastPacket(const CDvHeaderPacket &Header, CBuffer *Buffer) const
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','D' };
|
|
|
|
uint8 dest[] = { 'A','L','L',' ',' ',' ',' ',' ',' ',' ' };
|
|
|
|
char sz[YSF_CALLSIGN_LENGTH];
|
|
|
|
uint8 fichd[YSF_FICH_LENGTH_BYTES];
|
|
|
|
|
|
|
|
// tag
|
|
|
|
Buffer->Set(tag, sizeof(tag));
|
|
|
|
// rpt1
|
|
|
|
::memset(sz, ' ', sizeof(sz));
|
|
|
|
Header.GetRpt1Callsign().GetCallsignString(sz);
|
|
|
|
sz[::strlen(sz)] = ' ';
|
|
|
|
Buffer->Append((uint8 *)sz, YSF_CALLSIGN_LENGTH);
|
|
|
|
// my
|
|
|
|
::memset(sz, ' ', sizeof(sz));
|
|
|
|
Header.GetMyCallsign().GetCallsignString(sz);
|
|
|
|
sz[::strlen(sz)] = ' ';
|
|
|
|
Buffer->Append((uint8 *)sz, YSF_CALLSIGN_LENGTH);
|
|
|
|
// dest
|
|
|
|
Buffer->Append(dest, 10);
|
|
|
|
// net frame counter
|
|
|
|
Buffer->Append((uint8)0x00);
|
|
|
|
// FS
|
|
|
|
Buffer->Append((uint8 *)YSF_SYNC_BYTES, YSF_SYNC_LENGTH_BYTES);
|
|
|
|
// FICH
|
|
|
|
CYSFFICH fich;
|
|
|
|
fich.setFI(YSF_FI_TERMINATOR);
|
|
|
|
fich.setCS(2U);
|
|
|
|
//fich.setFN(Header.GetYsfPacketId());
|
|
|
|
fich.setFN(0U);
|
|
|
|
fich.setFT(7U);
|
|
|
|
fich.setDev(0U);
|
|
|
|
fich.setMR(YSF_MR_BUSY);
|
|
|
|
fich.setDT(YSF_DT_VD_MODE2);
|
|
|
|
fich.setSQL(0U);
|
|
|
|
fich.setSQ(0U);
|
|
|
|
fich.encode(fichd);
|
|
|
|
Buffer->Append(fichd, YSF_FICH_LENGTH_BYTES);
|
|
|
|
// payload
|
|
|
|
unsigned char csd1[20U], csd2[20U];
|
|
|
|
::memset(csd1, '*', YSF_CALLSIGN_LENGTH);
|
|
|
|
::memset(csd1 + YSF_CALLSIGN_LENGTH, ' ', YSF_CALLSIGN_LENGTH);
|
|
|
|
Header.GetMyCallsign().GetCallsignString(sz);
|
|
|
|
::memcpy(csd1 + YSF_CALLSIGN_LENGTH, sz, ::strlen(sz));
|
|
|
|
::memset(csd2, ' ', YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH);
|
|
|
|
CYSFPayload payload;
|
|
|
|
uint8 temp[120];
|
|
|
|
payload.writeHeader(temp, csd1, csd2);
|
|
|
|
Buffer->Append(temp+30, 120-30);
|
|
|
|
|
|
|
|
// done
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Wires-X packet decoding helpers
|
|
|
|
|
|
|
|
bool CYsfProtocol::IsValidwirexPacket(const CBuffer &Buffer, CYSFFICH *Fich, CCallsign *Callsign, int *Cmd, int *Arg)
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','D' };
|
|
|
|
uint8 DX_REQ[] = {0x5DU, 0x71U, 0x5FU};
|
|
|
|
uint8 CONN_REQ[] = {0x5DU, 0x23U, 0x5FU};
|
|
|
|
uint8 DISC_REQ[] = {0x5DU, 0x2AU, 0x5FU};
|
|
|
|
uint8 ALL_REQ[] = {0x5DU, 0x66U, 0x5FU};
|
|
|
|
uint8 command[300];
|
|
|
|
CYSFPayload payload;
|
|
|
|
bool valid = false;
|
|
|
|
|
|
|
|
if ( (Buffer.size() == 155) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
|
|
|
|
{
|
|
|
|
// decode YSH fich
|
|
|
|
if ( Fich->decode(&(Buffer.data()[40])) )
|
|
|
|
{
|
|
|
|
//std::cout << (int)Fich->getDT() << ","
|
|
|
|
// << (int)Fich->getFI() << ","
|
|
|
|
// << (int)Fich->getFN() << ","
|
|
|
|
// << (int)Fich->getFT()
|
|
|
|
// << std::endl;
|
|
|
|
valid = (Fich->getDT() == YSF_DT_DATA_FR_MODE);
|
|
|
|
valid &= (Fich->getFI() == YSF_FI_COMMUNICATIONS);
|
|
|
|
if ( valid )
|
|
|
|
{
|
|
|
|
// get callsign
|
|
|
|
Callsign->SetCallsign(&(Buffer.data()[4]), CALLSIGN_LEN, false);
|
|
|
|
Callsign->SetModule(YSF_MODULE_ID);
|
|
|
|
// decode payload
|
|
|
|
if ( Fich->getFN() == 0U )
|
|
|
|
{
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
else if ( Fich->getFN() == 1U )
|
|
|
|
{
|
|
|
|
valid &= payload.readDataFRModeData2(&(Buffer.data()[35]), command + 0U);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valid &= payload.readDataFRModeData1(&(Buffer.data()[35]), command + (Fich->getFN() - 1U) * 20U + 0U);
|
|
|
|
if ( valid )
|
|
|
|
{
|
|
|
|
valid &= payload.readDataFRModeData2(&(Buffer.data()[35]), command + (Fich->getFN() - 1U) * 20U + 20U);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// check crc if end found
|
|
|
|
if ( Fich->getFN() == Fich->getFT() )
|
|
|
|
{
|
|
|
|
valid = false;
|
|
|
|
// Find the end marker
|
|
|
|
for (unsigned int i = Fich->getFN() * 20U; i > 0U; i--)
|
|
|
|
{
|
|
|
|
if (command[i] == 0x03U)
|
|
|
|
{
|
|
|
|
unsigned char crc = CCRC::addCRC(command, i + 1U);
|
|
|
|
if (crc == command[i + 1U])
|
|
|
|
valid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// and crack the command
|
|
|
|
if ( valid )
|
|
|
|
{
|
|
|
|
// get argument
|
|
|
|
char buffer[4U];
|
|
|
|
::memcpy(buffer, command + 5U + 2U, 3U);
|
|
|
|
buffer[3U] = 0x00U;
|
|
|
|
*Arg = ::atoi(buffer);
|
|
|
|
// and decode command
|
|
|
|
if (::memcmp(command + 1U, DX_REQ, 3U) == 0)
|
|
|
|
{
|
|
|
|
*Cmd = WIRESX_CMD_DX_REQ;
|
|
|
|
*Arg = 0;
|
|
|
|
}
|
|
|
|
else if (::memcmp(command + 1U, ALL_REQ, 3U) == 0)
|
|
|
|
{
|
|
|
|
// argument is start index of list
|
|
|
|
if ( *Arg > 0 )
|
|
|
|
(*Arg)--;
|
|
|
|
// check if all or search
|
|
|
|
if ( ::memcmp(command + 5U, "01", 2) == 0 )
|
|
|
|
{
|
|
|
|
*Cmd = WIRESX_CMD_ALL_REQ;
|
|
|
|
}
|
|
|
|
else if ( ::memcmp(command + 5U, "11", 2) == 0 )
|
|
|
|
{
|
|
|
|
*Cmd = WIRESX_CMD_SEARCH_REQ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (::memcmp(command + 1U, CONN_REQ, 3U) == 0)
|
|
|
|
{
|
|
|
|
*Cmd = WIRESX_CMD_CONN_REQ;
|
|
|
|
}
|
|
|
|
else if (::memcmp(command + 1U, DISC_REQ, 3U) == 0)
|
|
|
|
{
|
|
|
|
*Cmd = WIRESX_CMD_DISC_REQ;
|
|
|
|
*Arg = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "Wires-X unknown command" << std::endl;
|
|
|
|
*Cmd = WIRESX_CMD_UNKNOWN;
|
|
|
|
*Arg = 0;
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
2020-01-04 05:17:22 -05:00
|
|
|
// server status packet decoding helpers
|
|
|
|
|
|
|
|
bool CYsfProtocol::IsValidServerStatusPacket(const CBuffer &Buffer) const
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','S' };
|
|
|
|
|
|
|
|
return ( (Buffer.size() >= 4) && (Buffer.Compare(tag, sizeof(tag)) == 0) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// server status packet encoding helpers
|
|
|
|
|
|
|
|
bool CYsfProtocol::EncodeServerStatusPacket(CBuffer *Buffer) const
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','S' };
|
2020-01-08 13:28:54 -05:00
|
|
|
uint8 description[] = { 'X','L','X',' ','r','e','f','l','e','c','t','o','r',' ' };
|
2020-01-04 05:17:22 -05:00
|
|
|
uint8 callsign[16];
|
|
|
|
|
|
|
|
// tag
|
|
|
|
Buffer->Set(tag, sizeof(tag));
|
|
|
|
// hash
|
|
|
|
::memset(callsign, ' ', sizeof(callsign));
|
|
|
|
g_Reflector.GetCallsign().GetCallsign(callsign);
|
|
|
|
char sz[16];
|
|
|
|
::sprintf(sz, "%05u", CalcHash(callsign, 16) % 100000U);
|
|
|
|
Buffer->Append((uint8 *)sz, 5);
|
|
|
|
// name
|
|
|
|
Buffer->Append(callsign, 16);
|
|
|
|
// desscription
|
2020-01-08 13:28:54 -05:00
|
|
|
Buffer->Append(description, 14);
|
2020-01-04 05:17:22 -05:00
|
|
|
// connected clients
|
|
|
|
CClients *clients = g_Reflector.GetClients();
|
|
|
|
int count = MIN(999, clients->GetSize());
|
|
|
|
g_Reflector.ReleaseClients();
|
|
|
|
::sprintf(sz, "%03u", count);
|
|
|
|
Buffer->Append((uint8 *)sz, 3);
|
|
|
|
|
|
|
|
// done
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CYsfProtocol::CalcHash(const uint8 *buffer, int len) const
|
|
|
|
{
|
|
|
|
uint32 hash = 0U;
|
|
|
|
|
|
|
|
for ( int i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
hash += buffer[i];
|
|
|
|
hash += (hash << 10);
|
|
|
|
hash ^= (hash >> 6);
|
|
|
|
}
|
|
|
|
hash += (hash << 3);
|
|
|
|
hash ^= (hash >> 11);
|
|
|
|
hash += (hash << 15);
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-26 09:25:15 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// uiStreamId helpers
|
|
|
|
|
|
|
|
|
|
|
|
// uiStreamId helpers
|
|
|
|
uint32 CYsfProtocol::IpToStreamId(const CIp &ip) const
|
|
|
|
{
|
|
|
|
return ip.GetAddr() ^ (uint32)(MAKEDWORD(ip.GetPort(), ip.GetPort()));
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// debug
|
|
|
|
|
|
|
|
#ifdef DEBUG_DUMPFILE
|
|
|
|
bool CYsfProtocol::DebugTestDecodePacket(const CBuffer &Buffer)
|
|
|
|
{
|
|
|
|
uint8 tag[] = { 'Y','S','F','D' };
|
|
|
|
static uint8 command[4098];
|
|
|
|
static int len;
|
|
|
|
CYSFFICH Fich;
|
|
|
|
CYSFPayload payload;
|
|
|
|
CBuffer dump;
|
|
|
|
bool valid = false;
|
|
|
|
|
|
|
|
if ( (Buffer.size() == 155) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
|
|
|
|
{
|
|
|
|
// decode YSH fich
|
|
|
|
if ( Fich.decode(&(Buffer.data()[40])) )
|
|
|
|
{
|
|
|
|
std::cout << (int)Fich.getDT() << ","
|
|
|
|
<< (int)Fich.getFI() << ","
|
|
|
|
<< (int)Fich.getBN() << ","
|
|
|
|
<< (int)Fich.getBT() << ","
|
|
|
|
<< (int)Fich.getFN() << ","
|
|
|
|
<< (int)Fich.getFT() << " : ";
|
|
|
|
|
|
|
|
switch ( Fich.getFI() )
|
|
|
|
{
|
|
|
|
case YSF_FI_HEADER:
|
|
|
|
len = 0;
|
|
|
|
::memset(command, 0x00, sizeof(command));
|
|
|
|
std::cout << "Header" << std::endl;
|
|
|
|
break;
|
|
|
|
case YSF_FI_TERMINATOR:
|
|
|
|
std::cout << "Trailer" << std::endl;
|
|
|
|
std::cout << "length of payload : " << len << std::endl;
|
|
|
|
dump.Set(command, len);
|
|
|
|
dump.DebugDump(g_Reflector.m_DebugFile);
|
|
|
|
dump.DebugDumpAscii(g_Reflector.m_DebugFile);
|
|
|
|
break;
|
|
|
|
case YSF_FI_COMMUNICATIONS:
|
|
|
|
if ( Fich.getDT() == YSF_DT_DATA_FR_MODE )
|
|
|
|
{
|
|
|
|
valid = payload.readDataFRModeData1(&(Buffer.data()[35]), command + len);
|
|
|
|
len += 20;
|
|
|
|
valid &= payload.readDataFRModeData2(&(Buffer.data()[35]), command + len);
|
|
|
|
len += 20;
|
|
|
|
std::cout << "decoded ok" << std::endl;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "invalid fich in packet" << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "invalid size packet" << std::endl;
|
|
|
|
}
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
bool CYsfProtocol::DebugDumpHeaderPacket(const CBuffer &Buffer)
|
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
CYSFFICH fich;
|
|
|
|
CYSFPayload payload;
|
|
|
|
uint8 data[200];
|
|
|
|
|
|
|
|
:: memset(data, 0, sizeof(data));
|
|
|
|
|
|
|
|
|
|
|
|
ok = IsValidDvPacket(Buffer, &fich);
|
|
|
|
if ( ok && (fich.getFI() == YSF_FI_HEADER) )
|
|
|
|
{
|
|
|
|
ok &= payload.processHeaderData((unsigned char *)&(Buffer.data()[35]));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "HD-" <<(ok ? "ok " : "xx ") << "src: " << payload.getSource() << "dest: " << payload.getDest() << std::endl;
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CYsfProtocol::DebugDumpDvPacket(const CBuffer &Buffer)
|
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
CYSFFICH fich;
|
|
|
|
CYSFPayload payload;
|
|
|
|
uint8 data[200];
|
|
|
|
|
|
|
|
:: memset(data, 0, sizeof(data));
|
|
|
|
|
|
|
|
ok = IsValidDvPacket(Buffer, &fich);
|
|
|
|
if ( ok && (fich.getFI() == YSF_FI_COMMUNICATIONS) )
|
|
|
|
{
|
|
|
|
ok &= payload.readVDMode2Data(&(Buffer.data()[35]), data);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "DV-" <<(ok ? "ok " : "xx ") << "FN:" << (int)fich.getFN() << " payload: " << (char *)data << std::endl;
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CYsfProtocol::DebugDumpLastDvPacket(const CBuffer &Buffer)
|
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
CYSFFICH fich;
|
|
|
|
CYSFPayload payload;
|
|
|
|
uint8 data[200];
|
|
|
|
|
|
|
|
:: memset(data, 0, sizeof(data));
|
|
|
|
|
|
|
|
|
|
|
|
ok = IsValidDvPacket(Buffer, &fich);
|
|
|
|
if ( ok && (fich.getFI() == YSF_FI_TERMINATOR) )
|
|
|
|
{
|
|
|
|
ok &= payload.processHeaderData((unsigned char *)&(Buffer.data()[35]));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "TC-" <<(ok ? "ok " : "xx ") << "src: " << payload.getSource() << "dest: " << payload.getDest() << std::endl;
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|