blob: 8514091432e767e2eebaa10ab3d679f6a37290c9 [file] [log] [blame]
//
// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include "GatordMockService.hpp"
#include <common/include/Assert.hpp>
#include <common/include/CommandHandlerRegistry.hpp>
#include <common/include/CommonProfilingUtils.hpp>
#include <common/include/PacketVersionResolver.hpp>
#include <common/include/NetworkSockets.hpp>
#include <cerrno>
#include <iostream>
#include <string>
namespace armnn
{
namespace gatordmock
{
void GatordMockService::SendConnectionAck()
{
if (m_EchoPackets)
{
std::cout << "Sending connection acknowledgement." << std::endl;
}
// The connection ack packet is an empty data packet with packetId == 1.
m_BasePipeServer.get()->SendPacket(0, 1, nullptr, 0);
}
void GatordMockService::SendRequestCounterDir()
{
if (m_EchoPackets)
{
std::cout << "Sending connection acknowledgement." << std::endl;
}
// The request counter directory packet is an empty data packet with packetId == 3.
m_BasePipeServer.get()->SendPacket(0, 3, nullptr, 0);
}
void GatordMockService::SendActivateTimelinePacket()
{
if (m_EchoPackets)
{
std::cout << "Sending activate timeline packet." << std::endl;
}
// The activate timeline packet is an empty data packet with packetId == 6.
m_BasePipeServer.get()->SendPacket(0, 6, nullptr, 0);
}
void GatordMockService::SendDeactivateTimelinePacket()
{
if (m_EchoPackets)
{
std::cout << "Sending deactivate timeline packet." << std::endl;
}
// The deactivate timeline packet is an empty data packet with packetId == 7.
m_BasePipeServer.get()->SendPacket(0, 7, nullptr, 0);
}
bool GatordMockService::LaunchReceivingThread()
{
if (m_EchoPackets)
{
std::cout << "Launching receiving thread." << std::endl;
}
// At this point we want to make the socket non blocking.
if (!m_BasePipeServer.get()->SetNonBlocking())
{
m_BasePipeServer.get()->Close();
std::cerr << "Failed to set socket as non blocking: " << strerror(errno) << std::endl;
return false;
}
m_ListeningThread = std::thread(&GatordMockService::ReceiveLoop, this);
return true;
}
void GatordMockService::WaitForReceivingThread()
{
// The receiving thread may already have died.
if (m_CloseReceivingThread != true)
{
m_CloseReceivingThread.store(true);
}
// Check that the receiving thread is running
if (m_ListeningThread.joinable())
{
// Wait for the receiving thread to complete operations
m_ListeningThread.join();
}
if(m_EchoPackets)
{
m_TimelineDecoder.print();
}
}
bool GatordMockService::WaitForStreamMetaData()
{
return m_BasePipeServer->WaitForStreamMetaData();
}
void GatordMockService::SendPeriodicCounterSelectionList(uint32_t period, std::vector<uint16_t> counters)
{
// The packet body consists of a UINT32 representing the period following by zero or more
// UINT16's representing counter UID's. If the list is empty it implies all counters are to
// be disabled.
if (m_EchoPackets)
{
std::cout << "SendPeriodicCounterSelectionList: Period=" << std::dec << period << "uSec" << std::endl;
std::cout << "List length=" << counters.size() << std::endl;
}
// Start by calculating the length of the packet body in bytes. This will be at least 4.
uint32_t dataLength = static_cast<uint32_t>(4 + (counters.size() * 2));
std::unique_ptr<unsigned char[]> uniqueData = std::make_unique<unsigned char[]>(dataLength);
unsigned char* data = reinterpret_cast<unsigned char*>(uniqueData.get());
uint32_t offset = 0;
arm::pipe::WriteUint32(data, offset, period);
offset += 4;
for (std::vector<uint16_t>::iterator it = counters.begin(); it != counters.end(); ++it)
{
arm::pipe::WriteUint16(data, offset, *it);
offset += 2;
}
// Send the packet.
m_BasePipeServer.get()->SendPacket(0, 4, data, dataLength);
// There will be an echo response packet sitting in the receive thread. PeriodicCounterSelectionResponseHandler
// should deal with it.
}
void GatordMockService::WaitCommand(uint32_t timeout)
{
// Wait for a maximum of timeout microseconds or if the receive thread has closed.
// There is a certain level of rounding involved in this timing.
uint32_t iterations = timeout / 1000;
std::cout << std::dec << "Wait command with timeout of " << timeout << " iterations = " << iterations << std::endl;
uint32_t count = 0;
while ((this->ReceiveThreadRunning() && (count < iterations)))
{
std::this_thread::sleep_for(std::chrono::microseconds(1000));
++count;
}
if (m_EchoPackets)
{
std::cout << std::dec << "Wait command with timeout of " << timeout << " microseconds completed. " << std::endl;
}
}
void GatordMockService::ReceiveLoop()
{
m_CloseReceivingThread.store(false);
while (!m_CloseReceivingThread.load())
{
try
{
arm::pipe::Packet packet = m_BasePipeServer.get()->WaitForPacket(500);
arm::pipe::PacketVersionResolver packetVersionResolver;
arm::pipe::Version version =
packetVersionResolver.ResolvePacketVersion(packet.GetPacketFamily(), packet.GetPacketId());
arm::pipe::CommandHandlerFunctor* commandHandlerFunctor = m_HandlerRegistry.GetFunctor(
packet.GetPacketFamily(),
packet.GetPacketId(),
version.GetEncodedValue());
ARM_PIPE_ASSERT(commandHandlerFunctor);
commandHandlerFunctor->operator()(packet);
}
catch (const arm::pipe::TimeoutException&)
{
// In this case we ignore timeouts and and keep trying to receive.
}
catch (const arm::pipe::InvalidArgumentException& e)
{
// We couldn't find a functor to handle the packet?
std::cerr << "Packet received that could not be processed: " << e.what() << std::endl;
}
catch (const arm::pipe::ProfilingException& e)
{
// A runtime exception occurred which means we must exit the loop.
std::cerr << "Receive thread closing: " << e.what() << std::endl;
m_CloseReceivingThread.store(true);
}
}
}
} // namespace gatordmock
} // namespace armnn