Skip to content

Commit

Permalink
Broker, SharpTerminal: added ClearEEProm cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
bcsanches committed Aug 21, 2024
1 parent 84eb6c2 commit 23bf8a8
Show file tree
Hide file tree
Showing 15 changed files with 341 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/BrokerLib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ add_library(
sys/Thinker.h
sys/ZeroConfSystem.cpp
sys/ZeroConfSystem.h
terminal/DeviceClearEEPromCmd.cpp
terminal/DeviceClearEEPromCmd.h
terminal/DeviceRenameCmd.cpp
terminal/DeviceRenameCmd.h
terminal/ServiceCmdBase.cpp
Expand Down
9 changes: 9 additions & 0 deletions src/BrokerLib/dcc/NetworkDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -993,4 +993,13 @@ namespace dcclite::broker

return task;
}

std::shared_ptr<NetworkTask> NetworkDevice::StartDeviceClearEEPromTask(NetworkTask::IObserver *observer)
{
auto task = detail::StartDeviceClearEEPromTask(*this, ++g_u32TaskId, observer);

m_lstTasks.push_back(task);

return task;
}
}
1 change: 1 addition & 0 deletions src/BrokerLib/dcc/NetworkDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ namespace dcclite::broker
[[nodiscard]] std::shared_ptr<NetworkTask> StartDownloadEEPromTask(NetworkTask::IObserver *observer, DownloadEEPromTaskResult_t &resultsStorage);
[[nodiscard]] std::shared_ptr<NetworkTask> StartServoTurnoutProgrammerTask(NetworkTask::IObserver *observer, RName servoDecoderName);
[[nodiscard]] std::shared_ptr<NetworkTask> StartDeviceRenameTask(NetworkTask::IObserver *observer, RName newName);
[[nodiscard]] std::shared_ptr<NetworkTask> StartDeviceClearEEPromTask(NetworkTask::IObserver *observer);

protected:
void OnUnload() override;
Expand Down
123 changes: 123 additions & 0 deletions src/BrokerLib/dcc/NetworkDeviceTasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,124 @@ namespace dcclite::broker::detail
++m_iCount;
}

/////////////////////////////////////////////////////////////////////////////
//
// ClearEEPromTask
//
/////////////////////////////////////////////////////////////////////////////

/**
* ClearEEPromTask Packet format
0 1 2 3 4 5 6 7
+--+--+--+--+--+--+--+--+
| NOTHING |
+--+--+--+--+--+--+--+--+
Timesequence:
1 - Send packet with task id
2 - Awaits confirmation packet
*/

class ClearEEPromTask: public NetworkTaskImpl
{
public:
ClearEEPromTask(INetworkDevice_TaskServices &owner, const uint32_t taskId, IObserver *observer):
NetworkTaskImpl{ owner, taskId, observer },
m_clThinker{ "ClearEEPromTask::Thinker", THINKER_MF_LAMBDA(OnThink) }
{
if (!m_rclOwner.IsConnectionStable())
throw std::runtime_error(fmt::format("[DeviceRenameTask] Cannot start a clear EEPROM task without a valid connection"));

//start running
m_clThinker.Schedule({});
}

void OnPacket(dcclite::Packet &packet, const dcclite::Clock::TimePoint_t time) override;

void Abort() noexcept override;
void Stop() noexcept override;

private:
void OnThink(const dcclite::Clock::TimePoint_t time);

private:
Thinker m_clThinker;

bool m_fWaitingAck = true;

int m_iCount = 0;
};

void ClearEEPromTask::Abort() noexcept
{
this->MarkAbort();
}

void ClearEEPromTask::Stop() noexcept
{
if (!this->HasFinished())
this->Abort();
}

void ClearEEPromTask::OnPacket(dcclite::Packet &packet, const dcclite::Clock::TimePoint_t time)
{
if (!m_fWaitingAck)
{
//ignore... late packet...
}

const auto ack = packet.ReadByte();
if (ack == 1)
{
m_fWaitingAck = false;

auto &owner = m_rclOwner;

this->MarkFinished();
}
else
{
this->MarkFailed(fmt::format("[ClearEEPromTask::OnPacket] Got invalid packet {}", ack));
}
}

void ClearEEPromTask::OnThink(const dcclite::Clock::TimePoint_t time)
{
assert(!this->HasFailed());
assert(!this->HasFinished());

if (!m_fWaitingAck)
{
//ignore... should not be here...
return;
}

if (m_iCount == 10)
{
Log::Error("[ClearEEPromTask::OnThink]: Too many retries, node does not ACK to clear EEPROM");

//too much retries... abort
this->MarkFailed("[ClearEEPromTask::OnThink] Too many retries, node does not ACK");

//Jim seems to be dead...
return;
}

Log::Trace("[ClearEEPromTask::OnThink]: requesting clear EEPROM");

dcclite::Packet packet;

m_rclOwner.TaskServices_FillPacketHeader(packet, m_u32TaskId, NetworkTaskTypes::TASK_CLEAR_EEPROM);

m_rclOwner.TaskServices_SendPacket(packet);
m_clThinker.Schedule(time + 50ms);

++m_iCount;
}

/////////////////////////////////////////////////////////////////////////////
//
// ServoTurnoutProgrammerTask
Expand Down Expand Up @@ -1093,4 +1211,9 @@ namespace dcclite::broker::detail
{
return std::make_shared<DeviceRenameTask>(owner, taskId, observer, newName);
}

std::shared_ptr<NetworkTaskImpl> StartDeviceClearEEPromTask(INetworkDevice_TaskServices &owner, const uint32_t taskId, NetworkTask::IObserver *observer)
{
return std::make_shared<ClearEEPromTask>(owner, taskId, observer);
}
}
6 changes: 6 additions & 0 deletions src/BrokerLib/dcc/NetworkDeviceTasks.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,5 +230,11 @@ namespace dcclite::broker
NetworkTask::IObserver *observer,
RName newName
);

extern std::shared_ptr<NetworkTaskImpl> StartDeviceClearEEPromTask(
INetworkDevice_TaskServices &owner,
const uint32_t taskId,
NetworkTask::IObserver *observer
);
}
}
110 changes: 110 additions & 0 deletions src/BrokerLib/terminal/DeviceClearEEPromCmd.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (C) 2019 - Bruno Sanches. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.

#include "DeviceClearEEPromCmd.h"

#include "FmtUtils.h"
#include "Util.h"

#include "../dcc/DccLiteService.h"
#include "../dcc/NetworkDevice.h"

#include "TerminalClient.h"
#include "TerminalUtils.h"

namespace dcclite::broker
{
class DeviceClearEEPromFiber: public TerminalCmdFiber, private NetworkTask::IObserver
{
public:
DeviceClearEEPromFiber(const CmdId_t id, TerminalContext &context, NetworkDevice &device):
TerminalCmdFiber(id, context),
m_spTask{ device.StartDeviceClearEEPromTask(this) }
{
if (!m_spTask)
throw TerminalCmdException("No task provided for DeviceClearEEPromFiber", id);
}

~DeviceClearEEPromFiber() = default;

private:
void OnNetworkTaskStateChanged(NetworkTask &task) override
{
assert(&task == m_spTask.get());

m_spTask->SetObserver(nullptr);

if (m_spTask->HasFailed())
{
m_rclContext.SendClientNotification(detail::MakeRpcErrorResponse(m_tCmdId, fmt::format("Clear EEPROM task failed: {}", m_spTask->GetMessage())));

//suicide, we are useless now
m_rclContext.DestroyFiber(*this);

return;
}

if (m_spTask->HasFinished())
{
auto msg = detail::MakeRpcResultMessage(m_tCmdId, [this](Result_t &results)
{
results.AddStringValue("classname", "ClearEEPromResult");
}
);

m_rclContext.SendClientNotification(msg);

//finally finished, so go away like MR. MEESEEKS
m_rclContext.DestroyFiber(*this);
}
}

private:
std::shared_ptr<NetworkTask> m_spTask;
};

/////////////////////////////////////////////////////////////////////////////
//
// RenameItemCmd
//
/////////////////////////////////////////////////////////////////////////////

TerminalCmd::CmdResult_t ClearEEPromCmd::Run(TerminalContext &context, const CmdId_t id, const rapidjson::Document &request)
{
auto item = context.GetItem();
if (!item->IsFolder())
{
throw TerminalCmdException(fmt::format("Current location {} is invalid", context.GetLocation().string()), id);
}
auto folder = static_cast<IFolderObject *>(item);

auto paramsIt = request.FindMember("params");
if (paramsIt->value.Size() < 1)
{
throw TerminalCmdException(fmt::format("Usage: {} <itemPath>", this->GetName()), id);
}

auto locationParam = paramsIt->value[0].GetString();
item = folder->TryNavigate(dcclite::Path_t(locationParam));
if (!item)
{
throw TerminalCmdException(fmt::format("Invalid location {}", locationParam), id);
}

auto networkDevice = dynamic_cast<NetworkDevice *>(item);
if (!networkDevice)
{
throw TerminalCmdException(fmt::format("Clear EEPROM operation only supported by NetworkDevice, {} is not a network device", networkDevice->GetName()), id);
}

return std::make_unique<DeviceClearEEPromFiber>(id, context, *networkDevice);
}
}

31 changes: 31 additions & 0 deletions src/BrokerLib/terminal/DeviceClearEEPromCmd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (C) 2019 - Bruno Sanches. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.


#pragma once

#include "ServiceCmdBase.h"

namespace dcclite::broker
{
class NetworkTask;

class ClearEEPromCmd: public DccLiteCmdBase
{
public:
explicit ClearEEPromCmd(RName name = RName{ "Clear-EEProm" }):
DccLiteCmdBase(name)
{
//empty
}

CmdResult_t Run(TerminalContext &context, const CmdId_t id, const rapidjson::Document &request) override;
};
}
5 changes: 5 additions & 0 deletions src/BrokerLib/terminal/TerminalService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "../sys/ServiceFactory.h"
#include "../sys/ZeroConfSystem.h"

#include "DeviceClearEEPromCmd.h"
#include "DeviceRenameCmd.h"
#include "ServiceCmdBase.h"
#include "ServoProgrammerCmds.h"
Expand Down Expand Up @@ -792,6 +793,10 @@ namespace dcclite::broker
cmdHost->AddCmd(std::make_unique<ResetItemCmd>());
}

{
cmdHost->AddCmd(std::make_unique<ClearEEPromCmd>());
}

{
cmdHost->AddCmd(std::make_unique<GetRNames>());
}
Expand Down
16 changes: 16 additions & 0 deletions src/Embedded/LiteDecoder/src/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,18 @@ static void RenameTaskHandler(dcclite::Packet &packet)
}
}

static void ClearEEPromTaskHandler(dcclite::Packet &packet)
{
const uint32_t taskId = packet.Read<uint32_t>();

Storage::Clear();

//always send ACK
Session::detail::InitTaskPacket(packet, taskId);
packet.Write8(1);
NetUdp::SendPacket(packet.GetData(), packet.GetSize(), g_u8ServerIp, g_uSrvPort);
}

static void OnTaskRequestPacket(dcclite::Packet &packet)
{
using namespace dcclite;
Expand All @@ -715,6 +727,10 @@ static void OnTaskRequestPacket(dcclite::Packet &packet)
RenameTaskHandler(packet);
break;

case NetworkTaskTypes::TASK_CLEAR_EEPROM:
ClearEEPromTaskHandler(packet);
break;

default:
//Console::SendLogEx(MODULE_NAME, FSTR_INVALID, ' ', "task", ' ', static_cast<int>(taskType));
DCCLITE_LOG_MODULE_LN(FSTR_INVALID << F(" task ") << static_cast<int>(taskType));
Expand Down
3 changes: 2 additions & 1 deletion src/Embedded/lib/Shared/Packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ namespace dcclite

TASK_DOWNLOAD_EEPROM,
TASK_SERVO_PROGRAMMER,
TASK_RENAME_DEVICE
TASK_RENAME_DEVICE,
TASK_CLEAR_EEPROM
};

enum class TaskRenameMsgTypes: uint8_t
Expand Down
2 changes: 1 addition & 1 deletion src/Emulator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ int main(int, char **)

TerminalService terminalService;

ArduinoLib::SetSerialInput("/cfg NoName;sv;");
//ArduinoLib::SetSerialInput("/cfg NoName;sv;");

dcclite::Clock clock;

Expand Down
Loading

0 comments on commit 23bf8a8

Please sign in to comment.