Skip to content

Commit

Permalink
⚡ (rc): Implement FileExchange actions
Browse files Browse the repository at this point in the history
  • Loading branch information
YannLocatelli committed Nov 25, 2022
1 parent bdc54fd commit 91fabb3
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 11 deletions.
1 change: 1 addition & 0 deletions libs/RobotKit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ if(${CMAKE_PROJECT_NAME} STREQUAL "LekaOSUnitTests")
tests/RobotController_test_stateWorking.cpp
tests/RobotController_test_stateEmergencyStopped.cpp
tests/RobotController_test_stateAutonomousActivities.cpp
tests/RobotController_test_stateFileExchange.cpp
)
endif()
endif()
49 changes: 41 additions & 8 deletions libs/RobotKit/include/RobotController.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,39 @@ class RobotController : public interface::RobotController
_activitykit.stop();
}

void onFileExchangeStart() final
{
_service_file_exchange.onFilePathReceived(
[this](std::span<const char> path) { file_reception.setFilePath(path.data()); });
_service_file_exchange.onFileDataReceived(
[this](std::span<const uint8_t> buffer) { file_reception.onPacketReceived(buffer); });
_service_file_exchange.onFileSHA256Requested([this](std::span<const char> path) {
if (FileManagerKit::File file {path.data()}; file.is_open()) {
_service_file_exchange.setFileSHA256(file.getSHA256());
}
});
}

void onFileExchangeEnd() final
{
_service_file_exchange.setFileExchangeState(false);

_service_file_exchange.onFilePathReceived(nullptr);
_service_file_exchange.onFileDataReceived(nullptr);
_service_file_exchange.onFileSHA256Requested(nullptr);
}

auto isReadyToFileExchange() -> bool final
{
auto is_robot_ready = (_battery.isCharging() && _battery.level() > _minimal_battery_level_to_update);

if (!is_robot_ready) {
_service_file_exchange.setFileExchangeState(false);
}

return is_robot_ready;
}

auto isReadyToUpdate() -> bool final
{
return (_battery.isCharging() && _battery.level() > _minimal_battery_level_to_update);
Expand Down Expand Up @@ -348,7 +381,9 @@ class RobotController : public interface::RobotController
_ble.setAdvertisingData(advertising_data);

_service_battery.setBatteryLevel(level);
if (is_charging) {

auto is_not_in_file_exchange = !_service_file_exchange.getFileExchangeState();
if (is_charging && is_not_in_file_exchange) {
onChargingBehavior(level);
}
});
Expand Down Expand Up @@ -395,13 +430,11 @@ class RobotController : public interface::RobotController
};
_service_commands.onCommandsReceived(on_commands_received);

_service_file_exchange.onFilePathReceived(
[this](std::span<const char> path) { file_reception.setFilePath(path.data()); });
_service_file_exchange.onFileDataReceived(
[this](std::span<const uint8_t> buffer) { file_reception.onPacketReceived(buffer); });
_service_file_exchange.onFileSHA256Requested([this](std::span<const char> path) {
if (FileManagerKit::File file {path.data()}; file.is_open()) {
_service_file_exchange.setFileSHA256(file.getSHA256());
_service_file_exchange.onSetFileExchangeState([this](bool file_exchange_requested) {
if (file_exchange_requested) {
raise(event::file_exchange_start_requested {});
} else {
raise(event::file_exchange_stop_requested {});
}
});

Expand Down
6 changes: 3 additions & 3 deletions libs/RobotKit/include/StateMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ namespace sm::guard {
};

struct is_ready_to_file_exchange {
auto operator()(irc &rc) const {}
auto operator()(irc &rc) const { return rc.isReadyToFileExchange(); }
};
struct is_ready_to_update {
auto operator()(irc &rc) const { return rc.isReadyToUpdate(); }
Expand Down Expand Up @@ -138,11 +138,11 @@ namespace sm::action {
};

struct on_file_exchange_start {
auto operator()(irc &rc) const {}
auto operator()(irc &rc) const { rc.onFileExchangeStart(); }
};

struct on_file_exchange_end {
auto operator()(irc &rc) const {}
auto operator()(irc &rc) const { rc.onFileExchangeEnd(); }
};

struct apply_update {
Expand Down
4 changes: 4 additions & 0 deletions libs/RobotKit/include/interface/RobotController.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class RobotController

virtual void startWorkingBehavior() = 0;

virtual void onFileExchangeStart() = 0;
virtual void onFileExchangeEnd() = 0;
virtual auto isReadyToFileExchange() -> bool = 0;

virtual auto isReadyToUpdate() -> bool = 0;
virtual void applyUpdate() = 0;

Expand Down
72 changes: 72 additions & 0 deletions libs/RobotKit/tests/RobotController_test_stateCharging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,78 @@ TEST_F(RobotControllerTest, stateChargingDisconnectedEventChargeDidStopGuardIsCh
EXPECT_TRUE(rc.state_machine.is(lksm::state::idle));
}

TEST_F(RobotControllerTest, stateChargingEventFileExchangeRequestedGuardIsReadyToFileExchangeTrue)
{
rc.state_machine.set_current_states(lksm::state::charging);

auto returned_is_charging = true;
auto returned_level = uint8_t {100};

// TODO (@yann): Trigger file_exchange_start_requested in StateMachine from BLE and do not use process_event

Sequence is_ready_to_file_exchange_sequence;
EXPECT_CALL(battery, isCharging)
.InSequence(is_ready_to_file_exchange_sequence)
.WillRepeatedly(Return(returned_is_charging));
EXPECT_CALL(battery, level).InSequence(is_ready_to_file_exchange_sequence).WillRepeatedly(Return(returned_level));

Sequence stop_charging_behavior;
EXPECT_CALL(timeout, stop).InSequence(stop_charging_behavior);

rc.state_machine.process_event(lksm::event::file_exchange_start_requested {});

EXPECT_TRUE(rc.state_machine.is(lksm::state::file_exchange));
}

TEST_F(RobotControllerTest, stateChargingEventFileExchangeRequestedGuardIsReadyToFileExchangeFalseNotCharging)
{
rc.state_machine.set_current_states(lksm::state::charging);

auto returned_is_charging = false;
auto returned_level = uint8_t {100};

// TODO (@yann): Trigger file_exchange_start_requested in StateMachine from BLE and do not use process_event

Sequence is_ready_to_file_exchange_sequence;
EXPECT_CALL(battery, isCharging)
.InSequence(is_ready_to_file_exchange_sequence)
.WillRepeatedly(Return(returned_is_charging));
EXPECT_CALL(battery, level).InSequence(is_ready_to_file_exchange_sequence).WillRepeatedly(Return(returned_level));
EXPECT_CALL(mbed_mock_gatt, write(_, _, _, _)).InSequence(is_ready_to_file_exchange_sequence);

Sequence stop_charging_behavior;
EXPECT_CALL(timeout, stop).Times(0).InSequence(stop_charging_behavior);

rc.state_machine.process_event(lksm::event::file_exchange_start_requested {});

EXPECT_TRUE(rc.state_machine.is(lksm::state::charging));
}

TEST_F(RobotControllerTest,
stateChargingEventFileExchangeRequestedGuardIsReadyToFileExchangeFalseBelowMinimalBatteryLevel)
{
rc.state_machine.set_current_states(lksm::state::charging);

auto returned_is_charging = true;
auto returned_level = uint8_t {0};

// TODO (@yann): Trigger file_exchange_start_requested in StateMachine from BLE and do not use process_event

Sequence is_ready_to_file_exchange_sequence;
EXPECT_CALL(battery, isCharging)
.InSequence(is_ready_to_file_exchange_sequence)
.WillRepeatedly(Return(returned_is_charging));
EXPECT_CALL(battery, level).InSequence(is_ready_to_file_exchange_sequence).WillRepeatedly(Return(returned_level));
EXPECT_CALL(mbed_mock_gatt, write(_, _, _, _)).InSequence(is_ready_to_file_exchange_sequence);

Sequence stop_charging_behavior;
EXPECT_CALL(timeout, stop).Times(0).InSequence(stop_charging_behavior);

rc.state_machine.process_event(lksm::event::file_exchange_start_requested {});

EXPECT_TRUE(rc.state_machine.is(lksm::state::charging));
}

TEST_F(RobotControllerTest, stateChargingEventUpdateRequestedGuardIsReadyToUpdateFalseNotCharging)
{
rc.state_machine.set_current_states(lksm::state::charging);
Expand Down
138 changes: 138 additions & 0 deletions libs/RobotKit/tests/RobotController_test_stateFileExchange.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Leka - LekaOS
// Copyright 2022 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#include "./RobotController_test.h"

TEST_F(RobotControllerTest, stateFileExchangeEventFileExchangeStopRequestedGuardIsCharging)
{
rc.state_machine.set_current_states(lksm::state::file_exchange);

auto returned_is_charging = true;

// TODO (@yann): Trigger file_exchange_stop_requested in StateMachine from BLE and do not use process_event

EXPECT_CALL(battery, isCharging).WillRepeatedly(Return(returned_is_charging));

Sequence on_file_exchange_end;
// TODO: Specify which BLE service and what is expected if necessary
EXPECT_CALL(mbed_mock_gatt, write(_, _, _, _)).Times(AnyNumber()).InSequence(on_file_exchange_end);

Sequence start_charging_behavior_sequence;
EXPECT_CALL(battery, level).InSequence(start_charging_behavior_sequence);
EXPECT_CALL(mock_videokit, displayImage).InSequence(start_charging_behavior_sequence);
EXPECT_CALL(mock_lcd, turnOn).InSequence(start_charging_behavior_sequence);
EXPECT_CALL(timeout, onTimeout).InSequence(start_charging_behavior_sequence);
EXPECT_CALL(timeout, start).InSequence(start_charging_behavior_sequence);

rc.state_machine.process_event(lksm::event::file_exchange_stop_requested {});

EXPECT_TRUE(rc.state_machine.is(lksm::state::charging));
}

TEST_F(RobotControllerTest, stateFileExchangeEventFileExchangeStopRequestedGuardIsNotCharging)
{
rc.state_machine.set_current_states(lksm::state::file_exchange);

auto returned_is_charging = false;

// TODO (@yann): Trigger file_exchange_stop_requested in StateMachine from BLE and do not use process_event

EXPECT_CALL(battery, isCharging).WillRepeatedly(Return(returned_is_charging));

Sequence on_file_exchange_end;
// TODO: Specify which BLE service and what is expected if necessary
EXPECT_CALL(mbed_mock_gatt, write(_, _, _, _)).Times(AnyNumber()).InSequence(on_file_exchange_end);

Sequence on_working_entry_sequence;
EXPECT_CALL(timeout, onTimeout).InSequence(on_working_entry_sequence);
EXPECT_CALL(timeout, start).InSequence(on_working_entry_sequence);
EXPECT_CALL(mock_videokit, displayImage).InSequence(on_working_entry_sequence);

rc.state_machine.process_event(lksm::event::file_exchange_stop_requested {});

EXPECT_TRUE(rc.state_machine.is(lksm::state::working));
}

TEST_F(RobotControllerTest, stateFileExchangeEventDisconnectionGuardIsCharging)
{
rc.state_machine.set_current_states(lksm::state::file_exchange, lksm::state::connected);

auto returned_is_charging = true;

// TODO (@yann): Trigger ble_disonnection in StateMachine from BLE and do not use process_event

EXPECT_CALL(battery, isCharging).WillRepeatedly(Return(returned_is_charging));

Sequence on_file_exchange_end;
// TODO: Specify which BLE service and what is expected if necessary
EXPECT_CALL(mbed_mock_gatt, write(_, _, _, _)).Times(AnyNumber()).InSequence(on_file_exchange_end);

EXPECT_CALL(mock_videokit, stopVideo).Times(2);
EXPECT_CALL(mock_motor_left, stop).Times(2);
EXPECT_CALL(mock_motor_right, stop).Times(2);
EXPECT_CALL(mock_ears, hide).Times(1);
EXPECT_CALL(mock_belt, hide).Times(1);

Sequence start_charging_behavior_sequence;
EXPECT_CALL(battery, level).InSequence(start_charging_behavior_sequence);
EXPECT_CALL(mock_videokit, displayImage).InSequence(start_charging_behavior_sequence);
EXPECT_CALL(mock_lcd, turnOn).InSequence(start_charging_behavior_sequence);
EXPECT_CALL(timeout, onTimeout).InSequence(start_charging_behavior_sequence);
EXPECT_CALL(timeout, start).InSequence(start_charging_behavior_sequence);

rc.state_machine.process_event(lksm::event::ble_disconnection {});

EXPECT_TRUE(rc.state_machine.is(lksm::state::charging, lksm::state::disconnected));
}

TEST_F(RobotControllerTest, stateFileExchangeEventDisconnectionGuardIsNotCharging)
{
rc.state_machine.set_current_states(lksm::state::file_exchange, lksm::state::connected);

auto returned_is_charging = false;

// TODO (@yann): Trigger ble_disonnection in StateMachine from BLE and do not use process_event

EXPECT_CALL(battery, isCharging).WillRepeatedly(Return(returned_is_charging));

Sequence on_file_exchange_end;
// TODO: Specify which BLE service and what is expected if necessary
EXPECT_CALL(mbed_mock_gatt, write(_, _, _, _)).Times(AnyNumber()).InSequence(on_file_exchange_end);

EXPECT_CALL(mock_videokit, stopVideo).Times(2);
EXPECT_CALL(mock_motor_left, stop).Times(2);
EXPECT_CALL(mock_motor_right, stop).Times(2);
EXPECT_CALL(mock_ears, hide).Times(1);
EXPECT_CALL(mock_belt, hide).Times(1);

Sequence on_idle_sequence;
EXPECT_CALL(timeout, onTimeout).InSequence(on_idle_sequence);
EXPECT_CALL(timeout, start).InSequence(on_idle_sequence);
EXPECT_CALL(mock_videokit, playVideoOnRepeat).InSequence(on_idle_sequence);
EXPECT_CALL(mock_lcd, turnOn).InSequence(on_idle_sequence);

rc.state_machine.process_event(lksm::event::ble_disconnection {});

EXPECT_TRUE(rc.state_machine.is(lksm::state::idle, lksm::state::disconnected));
}

TEST_F(RobotControllerTest, stateFileExchangeEventEmergencyStop)
{
rc.state_machine.set_current_states(lksm::state::file_exchange);

Sequence on_file_exchange_end;
// TODO: Specify which BLE service and what is expected if necessary
EXPECT_CALL(mbed_mock_gatt, write(_, _, _, _)).Times(AnyNumber()).InSequence(on_file_exchange_end);

EXPECT_CALL(mock_motor_left, stop).Times(2);
EXPECT_CALL(mock_motor_right, stop).Times(2);
EXPECT_CALL(mock_belt, hide).Times(1);
EXPECT_CALL(mock_ears, hide).Times(1);
EXPECT_CALL(mock_lcd, turnOff).Times(1);
EXPECT_CALL(mock_videokit, stopVideo).Times(2);

rc.onMagicCardAvailable(MagicCard::emergency_stop);

EXPECT_TRUE(rc.state_machine.is(lksm::state::emergency_stopped));
}
4 changes: 4 additions & 0 deletions libs/RobotKit/tests/mocks/RobotController.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ struct RobotController : public interface::RobotController {
MOCK_METHOD(void, startAutonomousActivityMode, (), (override));
MOCK_METHOD(void, stopAutonomousActivityMode, (), (override));

MOCK_METHOD(void, onFileExchangeStart, (), (override));
MOCK_METHOD(void, onFileExchangeEnd, (), (override));
MOCK_METHOD(bool, isReadyToFileExchange, (), (override));

MOCK_METHOD(bool, isReadyToUpdate, (), (override));
MOCK_METHOD(void, applyUpdate, (), (override));

Expand Down

0 comments on commit 91fabb3

Please sign in to comment.