Skip to content

Commit

Permalink
Adds implementation of factory_reset command. (#624)
Browse files Browse the repository at this point in the history
* Adds implementation of factory_reset command.

Adds unit test for factory reset and reboot commands.

* Adds a reboot after the factory reset is complete and quiesced.

* Removes wrong comment.
  • Loading branch information
balazsracz authored Jun 6, 2022
1 parent 1e0c2df commit e50296c
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 1 deletion.
17 changes: 17 additions & 0 deletions src/openlcb/MemoryConfig.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include "can_ioctl.h"
#endif

#include "openlcb/ConfigUpdateFlow.hxx"

extern "C" {
/// Implement this function (usually in HwInit.cxx) to enter the
/// bootloader. Usual implementations write some magic value to RAM and the
Expand All @@ -65,6 +67,21 @@ void reboot()
namespace openlcb
{

#ifdef GTEST
static constexpr unsigned FACTORY_RESET_REBOOT_DELAY_MSEC = 50;
#else
static constexpr unsigned FACTORY_RESET_REBOOT_DELAY_MSEC = 500;
#endif


void __attribute__((weak)) MemoryConfigHandler::handle_factory_reset()
{
static_cast<ConfigUpdateFlow *>(ConfigUpdateFlow::instance())
->factory_reset();
(new RebootTimer(service()))
->start(MSEC_TO_NSEC(FACTORY_RESET_REBOOT_DELAY_MSEC));
}

FileMemorySpace::FileMemorySpace(int fd, address_t len)
: fileSize_(len)
, name_(nullptr)
Expand Down
59 changes: 58 additions & 1 deletion src/openlcb/MemoryConfig.cxxtest
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
* @date 23 Feb 2014
*/

#include "utils/async_datagram_test_helper.hxx"
#include "openlcb/MemoryConfig.hxx"

#include "utils/async_datagram_test_helper.hxx"
#include "utils/ConfigUpdateListener.hxx"
#include "openlcb/ConfigUpdateFlow.hxx"

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
Expand Down Expand Up @@ -372,6 +375,60 @@ TEST_F(MemoryConfigTest, GetSpaceInfoRO_NZLA)
wait();
}

struct GlobalMock : public Singleton<GlobalMock> {
MOCK_METHOD0(reboot, void());
MOCK_METHOD0(factory_reset, void());
};

extern "C" void reboot()
{
GlobalMock::instance()->reboot();
}

struct FactoryResetListener : public DefaultConfigUpdateListener
{
void factory_reset(int fd) override
{
GlobalMock::instance()->factory_reset();
}

UpdateAction apply_configuration(
int fd, bool initial_load, BarrierNotifiable *done)
{
done->notify();
return UPDATED;
}
};

TEST_F(MemoryConfigTest, Reboot)
{
StrictMock<GlobalMock> mock;
// Normally, a reboot function never returns. We can't do that under linux
// though, so the stack will generate an error datagram reply.
expect_packet(":X19A4822AN077C1041;"); // unsupported command

EXPECT_CALL(mock, reboot());
send_packet(":X1A22A77CN20A9;");
wait();
}

TEST_F(MemoryConfigTest, FactoryReset)
{
StrictMock<GlobalMock> mock;
ConfigUpdateFlow update_flow{ifCan_.get()};
update_flow.TEST_set_fd(23);

FactoryResetListener l;
expect_packet(":X19A2822AN077C00;"); // received OK, no response

EXPECT_CALL(mock, factory_reset());
send_packet(":X1A22A77CN20AA;");
wait();

EXPECT_CALL(mock, reboot());
twait();
}

static const char MEMORY_BLOCK_DATA[] = "abrakadabra12345678xxxxyyyyzzzzwww.";

class StaticBlockTest : public MemoryConfigTest
Expand Down
25 changes: 25 additions & 0 deletions src/openlcb/MemoryConfig.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,11 @@ private:
#endif
return respond_reject(Defs::ERROR_UNIMPLEMENTED_SUBCMD);
}
case MemoryConfigDefs::COMMAND_FACTORY_RESET:
{
handle_factory_reset();
return respond_ok(0);
}
case MemoryConfigDefs::COMMAND_OPTIONS:
{
return call_immediately(STATE(handle_options));
Expand Down Expand Up @@ -513,6 +518,26 @@ private:
}
}

/// Used internally by the factory_reset implementation to reboot the
/// binary asynchronously.
class RebootTimer : public ::Timer
{
public:
RebootTimer(Service *s)
: ::Timer(s->executor()->active_timers())
{ }

long long timeout() override
{
reboot();
return DELETE;
}
};

/// Invokes the openlcb config handler to do a factory reset. Starts a
/// timer to reboot the device after a little time.
void handle_factory_reset();

Action ok_response_sent() OVERRIDE
{
if (!response_.empty())
Expand Down

0 comments on commit e50296c

Please sign in to comment.