LCOV - code coverage report
Current view: top level - src/drivers/vehicle_interface/src - safety_state_machine.cpp (source / functions) Hit Total Coverage
Test: lcov.total.filtered Lines: 149 165 90.3 %
Date: 2023-03-03 05:44:19 Functions: 19 21 90.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 108 164 65.9 %

           Branch data     Line data    Source code
       1                 :            : // Copyright 2020 the Autoware Foundation
       2                 :            : //
       3                 :            : // Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            : // you may not use this file except in compliance with the License.
       5                 :            : // You may obtain a copy of the License at
       6                 :            : //
       7                 :            : //     http://www.apache.org/licenses/LICENSE-2.0
       8                 :            : //
       9                 :            : // Unless required by applicable law or agreed to in writing, software
      10                 :            : // distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            : // See the License for the specific language governing permissions and
      13                 :            : // limitations under the License.
      14                 :            : //
      15                 :            : // Co-developed by Tier IV, Inc. and Apex.AI, Inc.
      16                 :            : #include <common/types.hpp>
      17                 :            : #include <helper_functions/float_comparisons.hpp>
      18                 :            : 
      19                 :            : #include <time_utils/time_utils.hpp>
      20                 :            : 
      21                 :            : #include <cmath>
      22                 :            : #include <limits>
      23                 :            : 
      24                 :            : #include "vehicle_interface/safety_state_machine.hpp"
      25                 :            : 
      26                 :            : #include "autoware_auto_vehicle_msgs/msg/headlights_command.hpp"
      27                 :            : #include "autoware_auto_vehicle_msgs/msg/headlights_report.hpp"
      28                 :            : #include "autoware_auto_vehicle_msgs/msg/horn_command.hpp"
      29                 :            : #include "autoware_auto_vehicle_msgs/msg/horn_report.hpp"
      30                 :            : #include "autoware_auto_vehicle_msgs/msg/wipers_command.hpp"
      31                 :            : #include "autoware_auto_vehicle_msgs/msg/wipers_report.hpp"
      32                 :            : 
      33                 :            : using autoware::common::types::bool8_t;
      34                 :            : namespace comp = autoware::common::helper_functions::comparisons;
      35                 :            : 
      36                 :            : namespace autoware
      37                 :            : {
      38                 :            : namespace drivers
      39                 :            : {
      40                 :            : namespace vehicle_interface
      41                 :            : {
      42                 :            : namespace
      43                 :            : {
      44                 :            : using VSC = autoware_auto_vehicle_msgs::msg::VehicleStateCommand;
      45                 :            : using VSR = StateReport;
      46                 :            : using autoware_auto_vehicle_msgs::msg::HeadlightsCommand;
      47                 :            : using autoware_auto_vehicle_msgs::msg::HeadlightsReport;
      48                 :            : using autoware_auto_vehicle_msgs::msg::HornCommand;
      49                 :            : using autoware_auto_vehicle_msgs::msg::HornReport;
      50                 :            : using autoware_auto_vehicle_msgs::msg::WipersCommand;
      51                 :            : using autoware_auto_vehicle_msgs::msg::WipersReport;
      52                 :            : static_assert(VSC::BLINKER_OFF == VSR::BLINKER_OFF, "BLINKER_OFF!=");
      53                 :            : static_assert(VSC::BLINKER_LEFT == VSR::BLINKER_LEFT, "BLINKER_LEFT !=");
      54                 :            : static_assert(VSC::BLINKER_RIGHT == VSR::BLINKER_RIGHT, "BLINKER_RIGHT !=");
      55                 :            : static_assert(VSC::BLINKER_HAZARD == VSR::BLINKER_HAZARD, "BLINKER_HAZARD !=");
      56                 :            : static_assert(HeadlightsCommand::DISABLE == VSR::HEADLIGHT_OFF, "HEADLIGHT_OFF !=");
      57                 :            : static_assert(HeadlightsCommand::ENABLE_LOW == VSR::HEADLIGHT_ON, "HEADLIGHT_ON !=");
      58                 :            : static_assert(HeadlightsCommand::ENABLE_HIGH == VSR::HEADLIGHT_HIGH, "HEADLIGHT_HIGH !=");
      59                 :            : static_assert(WipersCommand::DISABLE == WipersReport::DISABLE, "DISABLE !=");
      60                 :            : static_assert(WipersCommand::ENABLE_LOW == WipersReport::ENABLE_LOW, "ENABLE_LOW !=");
      61                 :            : static_assert(WipersCommand::ENABLE_HIGH == WipersReport::ENABLE_HIGH, "ENABLE_HIGH !=");
      62                 :            : static_assert(WipersCommand::ENABLE_CLEAN == WipersReport::ENABLE_CLEAN, "ENABLE_CLEAN !=");
      63                 :            : static_assert(VSC::GEAR_DRIVE == VSR::GEAR_DRIVE, "GEAR_DRIVE !=");
      64                 :            : static_assert(VSC::GEAR_REVERSE == VSR::GEAR_REVERSE, "GEAR_REVERSE !=");
      65                 :            : static_assert(VSC::GEAR_PARK == VSR::GEAR_PARK, "GEAR_PARK !=");
      66                 :            : static_assert(VSC::GEAR_LOW == VSR::GEAR_LOW, "GEAR_LOW !=");
      67                 :            : static_assert(VSC::GEAR_NEUTRAL == VSR::GEAR_NEUTRAL, "GEAR_NEUTRAL !=");
      68                 :            : static_assert(VSC::MODE_AUTONOMOUS == VSR::MODE_AUTONOMOUS, "MODE_AUTONOMOUS !=");
      69                 :            : static_assert(VSC::MODE_MANUAL == VSR::MODE_MANUAL, "MODE_MANUAL !=");
      70                 :            : }  // namespace
      71                 :            : 
      72                 :            : using VCC = autoware_auto_vehicle_msgs::msg::VehicleControlCommand;
      73                 :            : 
      74                 :            : ////////////////////////////////////////////////////////////////////////////////
      75                 :        141 : StateMachineConfig::StateMachineConfig(
      76                 :            :   const VelocityT gear_shift_velocity_threshold,
      77                 :            :   const AccelLimits & accel_limits,
      78                 :            :   const FrontWheelLimits & front_wheel_limits,
      79                 :            :   const std::chrono::nanoseconds time_step,
      80                 :            :   const AccelT timeout_accel_mps2,
      81                 :            :   const std::chrono::nanoseconds state_transition_timeout,
      82                 :        141 :   const AccelT auto_gear_shift_accel_deadzone_mps2)
      83                 :            : : m_gear_shift_velocity_threshold{gear_shift_velocity_threshold},
      84                 :            :   m_accel_limits{accel_limits},
      85                 :            :   m_front_wheel_limits{front_wheel_limits},
      86                 :            :   m_time_step{time_step},
      87                 :            :   m_timeout_acceleration{timeout_accel_mps2},
      88                 :            :   m_state_transition_timeout{state_transition_timeout},
      89                 :        141 :   m_auto_gear_shift_accel_deadzone{auto_gear_shift_accel_deadzone_mps2}
      90                 :            : {
      91         [ -  + ]:        141 :   if (VelocityT{} >= gear_shift_velocity_threshold) {
      92         [ #  # ]:          0 :     throw std::domain_error{"Gear shift velocity threshold must be positive"};
      93                 :            :   }
      94         [ -  + ]:        141 :   if (decltype(time_step)::zero() >= time_step) {
      95         [ #  # ]:          0 :     throw std::domain_error{"Time step must be positive"};
      96                 :            :   }
      97         [ -  + ]:        141 :   if (AccelT{} >= timeout_accel_mps2) {
      98         [ #  # ]:          0 :     throw std::domain_error{"Timeout acceleration must be > 0"};
      99                 :            :   }
     100   [ +  -  -  + ]:        141 :   if ((timeout_accel_mps2 < accel_limits.min()) || (timeout_accel_mps2 > accel_limits.max())) {
     101         [ #  # ]:          0 :     throw std::domain_error{"Timeout acceleration outside of acceleration limits"};
     102                 :            :   }
     103         [ -  + ]:        141 :   if (state_transition_timeout < time_step) {
     104         [ #  # ]:          0 :     throw std::domain_error{"State transition timeout must be > time_step"};
     105                 :            :   }
     106         [ -  + ]:        141 :   if (AccelT{} >= auto_gear_shift_accel_deadzone_mps2) {
     107         [ #  # ]:          0 :     throw std::domain_error{"Gear shift acceleration deadzone must be > 0"};
     108                 :            :   }
     109                 :        141 : }
     110                 :            : 
     111                 :        119 : StateMachineConfig::VelocityT StateMachineConfig::gear_shift_velocity_threshold() const noexcept
     112                 :            : {
     113                 :        119 :   return m_gear_shift_velocity_threshold;
     114                 :            : }
     115                 :            : 
     116                 :        141 : const StateMachineConfig::AccelLimits & StateMachineConfig::accel_limits() const noexcept
     117                 :            : {
     118                 :        141 :   return m_accel_limits;
     119                 :            : }
     120                 :            : 
     121                 :        136 : const StateMachineConfig::FrontWheelLimits & StateMachineConfig::front_wheel_limits() const noexcept
     122                 :            : {
     123                 :        136 :   return m_front_wheel_limits;
     124                 :            : }
     125                 :            : 
     126                 :         47 : std::chrono::nanoseconds StateMachineConfig::time_step() const noexcept {return m_time_step;}
     127                 :            : 
     128                 :          5 : StateMachineConfig::AccelT StateMachineConfig::timeout_acceleration() const noexcept
     129                 :            : {
     130                 :          5 :   return m_timeout_acceleration;
     131                 :            : }
     132                 :            : 
     133                 :       1289 : std::chrono::nanoseconds StateMachineConfig::state_transition_timeout() const noexcept
     134                 :            : {
     135                 :       1289 :   return m_state_transition_timeout;
     136                 :            : }
     137                 :            : 
     138                 :        149 : StateMachineConfig::AccelT StateMachineConfig::auto_gear_shift_accel_deadzone() const noexcept
     139                 :            : {
     140                 :        149 :   return m_auto_gear_shift_accel_deadzone;
     141                 :            : }
     142                 :            : 
     143                 :            : ////////////////////////////////////////////////////////////////////////////////
     144                 :            : ////////////////////////////////////////////////////////////////////////////////
     145                 :        139 : SafetyStateMachine::SafetyStateMachine(const StateMachineConfig & config)
     146         [ +  - ]:        139 : : m_config{config}
     147                 :            : {
     148         [ +  - ]:        139 :   m_reports.reserve(10U);  // Number of enums
     149                 :            :   {  // initialize state to something sensible
     150                 :        139 :     m_state.gear = VSR::GEAR_DRIVE;
     151                 :        139 :     m_state.blinker = VSR::BLINKER_OFF;
     152                 :        139 :     m_state.wiper = VSR::WIPER_OFF;
     153                 :        139 :     m_state.headlight = VSR::HEADLIGHT_OFF;
     154                 :        139 :     m_state.mode = VSR::MODE_NOT_READY;
     155                 :        139 :     m_state.horn = false;
     156                 :        139 :     m_state.hand_brake = false;
     157                 :            :   }
     158                 :        139 : }
     159                 :            : 
     160                 :            : ////////////////////////////////////////////////////////////////////////////////
     161                 :        136 : Command SafetyStateMachine::compute_safe_commands(const Command & command)
     162                 :            : {
     163         [ -  + ]:        136 :   m_reports.clear();
     164                 :        136 :   const auto control = clamp(command.control());
     165                 :            :   MaybeStateCommand state{command.state()};
     166         [ +  + ]:        136 :   if (command.state()) {
     167                 :            :     // Sanitize state command
     168         [ +  - ]:        226 :     state = sanitize(command.state().value());
     169                 :            :     // Apply headlight logic
     170                 :            :     const auto new_headlight = headlights_on_if_wipers_on(state.value());
     171         [ +  + ]:        113 :     if (new_headlight) {
     172                 :         10 :       state->headlight = new_headlight.value();
     173                 :         10 :       m_reports.emplace_back(StateMachineReport::WIPERS_ON_HEADLIGHTS_ON);
     174                 :            :     }
     175                 :            :     // Apply automatic gear shift logic: no command if already in that state
     176                 :            :     {
     177                 :        113 :       const auto requested_gear = automatic_gear_shift(control, state.value());
     178   [ +  +  +  - ]:        161 :       state->gear = (requested_gear == m_state.gear) ? VSC::GEAR_NO_COMMAND : requested_gear;
     179                 :            :     }
     180                 :            :     // Apply gear check logic
     181         [ +  + ]:        113 :     if (bad_gear_shift(state.value())) {
     182                 :          7 :       state->gear = VSC::GEAR_NO_COMMAND;
     183                 :          7 :       m_reports.emplace_back(StateMachineReport::REMOVE_GEAR_COMMAND);
     184                 :            :     }
     185                 :            :     // Add requests to queue
     186                 :        113 :     cache_state_change_request(state.value());
     187                 :            :   } else {
     188                 :            :     // Check if you need to do gear shifting
     189                 :            :     //lint -e{1793} NOLINT nonconst member on temp ok: named parameter idiom
     190                 :         23 :     const auto dummy_state = VSC{}.set__gear(m_state.gear);
     191                 :         23 :     const auto requested_gear = automatic_gear_shift(control, dummy_state);
     192         [ +  + ]:         23 :     if (requested_gear != m_state.gear) {
     193                 :            :       state = VSC{};
     194                 :          4 :       state->stamp = control.stamp;
     195                 :          4 :       state->gear = requested_gear;
     196                 :            :     }
     197                 :            :   }
     198                 :        136 :   return Command{control, state};
     199                 :            : }
     200                 :            : 
     201                 :            : ////////////////////////////////////////////////////////////////////////////////
     202         [ +  + ]:       1195 : void SafetyStateMachine::update(const Odometry & odom, const StateReport & state)
     203                 :            : {
     204                 :            :   m_reports.clear();
     205                 :            :   // TODO(c.ho) sanitize StateReport
     206                 :       1195 :   m_odometry = odom;
     207                 :       1195 :   m_state = state;
     208                 :            :   // Check if state update has been satisfied
     209                 :       1195 :   check_state_change(state);
     210                 :       1195 : }
     211                 :            : 
     212                 :            : ////////////////////////////////////////////////////////////////////////////////
     213                 :          5 : Command SafetyStateMachine::timeout_commands() const noexcept
     214                 :            : {
     215                 :            :   //lint -e{1793} NOLINT temporary ok: named parameter idiom
     216                 :            :   const auto state = VSC{}.set__blinker(VSC::BLINKER_HAZARD);
     217                 :            :   using Accel = decltype(BasicControlCommand::long_accel_mps2);
     218                 :         10 :   auto acceleration = -m_odometry.velocity_mps /
     219                 :          5 :     std::chrono::duration_cast<std::chrono::duration<Accel>>(m_config.time_step()).count();
     220                 :          5 :   (void)m_config.accel_limits().clamp_warn(acceleration);
     221                 :            :   //lint -e{1793} NOLINT temporary ok: named parameter idiom
     222                 :            :   const auto control = BasicControlCommand{}.set__long_accel_mps2(acceleration);
     223                 :          5 :   return Command{control, state};
     224                 :            : }
     225                 :            : 
     226                 :            : ////////////////////////////////////////////////////////////////////////////////
     227                 :       1165 : const SafetyStateMachine::Reports & SafetyStateMachine::reports() const noexcept
     228                 :            : {
     229                 :       1165 :   return m_reports;
     230                 :            : }
     231                 :            : 
     232                 :            : ////////////////////////////////////////////////////////////////////////////////
     233                 :          0 : const StateMachineConfig & SafetyStateMachine::get_config() const noexcept
     234                 :            : {
     235                 :          0 :   return m_config;
     236                 :            : }
     237                 :            : 
     238                 :            : ////////////////////////////////////////////////////////////////////////////////
     239                 :          0 : SafetyStateMachine::MaybeEnum SafetyStateMachine::headlights_on_if_wipers_on(const VSC & in)
     240                 :            : {
     241                 :          0 :   MaybeEnum ret{};
     242   [ -  -  +  + ]:        113 :   switch (in.wiper) {
     243                 :         14 :     case WipersCommand::ENABLE_LOW:
     244                 :            :     case WipersCommand::ENABLE_HIGH:
     245   [ -  -  +  + ]:         14 :       switch (in.headlight) {
     246                 :            :         case HeadlightsCommand::DISABLE:
     247                 :            :         case HeadlightsCommand::NO_COMMAND:
     248                 :            :           ret = MaybeEnum{HeadlightsCommand::ENABLE_LOW};
     249                 :         10 :           break;
     250                 :            :         case HeadlightsCommand::ENABLE_LOW:
     251                 :            :         case HeadlightsCommand::ENABLE_HIGH:
     252                 :            :         default:  // throw on other cases?
     253                 :            :           break;
     254                 :            :       }
     255                 :            :       break;
     256                 :            :     case WipersCommand::DISABLE:
     257                 :            :     case WipersCommand::ENABLE_CLEAN:
     258                 :            :     case WipersCommand::NO_COMMAND:
     259                 :            :     default:  // Throw on other cases?
     260                 :            :       break;
     261                 :            :   }
     262                 :          0 :   return ret;
     263                 :            : }
     264                 :            : 
     265                 :            : ////////////////////////////////////////////////////////////////////////////////
     266                 :        113 : bool8_t SafetyStateMachine::bad_gear_shift(const VSC & in) const
     267                 :            : {
     268                 :            :   // Doing nothing -> no check needed
     269         [ +  + ]:        113 :   if (VSC::GEAR_NO_COMMAND == in.gear) {
     270                 :            :     return false;
     271                 :            :   }
     272                 :            :   // Low velocity -> no check needed
     273                 :            :   const auto velocity_over_threshold =
     274         [ +  + ]:         35 :     (m_odometry.velocity_mps > m_config.gear_shift_velocity_threshold()) ||
     275         [ +  + ]:         31 :     (m_odometry.velocity_mps < -m_config.gear_shift_velocity_threshold());
     276                 :            :   if (!velocity_over_threshold) {
     277                 :            :     return false;
     278                 :            :   }
     279                 :            :   // If start and end start are not both forward -> bad
     280                 :          7 :   const auto going_forward =
     281                 :          7 :     (StateReport::GEAR_DRIVE == m_state.gear) || (StateReport::GEAR_LOW == m_state.gear);
     282                 :          7 :   const auto target_forward = (VSC::GEAR_DRIVE == in.gear) || (VSC::GEAR_LOW == in.gear);
     283         [ +  + ]:          7 :   if (going_forward != target_forward) {
     284                 :            :     return true;
     285                 :            :   }
     286                 :            :   // Otherwise if start and end state (park or reverse) are not the same -> bad
     287                 :            :   static_assert(VSC::GEAR_REVERSE == StateReport::GEAR_REVERSE, "VSC::reverse != VSR::reverse");
     288                 :            :   static_assert(VSC::GEAR_PARK == StateReport::GEAR_PARK, "VSC::park != VSR::park");
     289                 :          1 :   return m_state.gear != in.gear;
     290                 :            : }
     291                 :            : 
     292                 :            : ////////////////////////////////////////////////////////////////////////////////
     293                 :        136 : uint8_t SafetyStateMachine::automatic_gear_shift(
     294                 :            :   const BasicControlCommand control,
     295                 :            :   const VSC & state) const
     296                 :            : {
     297                 :            :   // If you're specifically asking for a park, I'll respect that and let other logic check
     298         [ +  + ]:        136 :   if (VSC::GEAR_PARK == state.gear) {
     299                 :            :     return state.gear;
     300                 :            :   }
     301                 :            :   // Small acceleration -> no check; let other logic handle
     302                 :            :   using Real = decltype(control.long_accel_mps2);
     303         [ +  + ]:        127 :   if (std::fabs(control.long_accel_mps2) < m_config.auto_gear_shift_accel_deadzone()) {
     304                 :        106 :     return state.gear;
     305                 :            :   }
     306                 :            :   // High velocity -> no check needed: let other logic handle
     307                 :         21 :   const auto velocity = m_odometry.velocity_mps;
     308         [ +  + ]:         21 :   const auto velocity_over_threshold = (velocity > m_config.gear_shift_velocity_threshold()) ||
     309         [ +  + ]:         18 :     (velocity < -m_config.gear_shift_velocity_threshold());
     310                 :            :   if (velocity_over_threshold) {
     311                 :          6 :     return state.gear;
     312                 :            :   }
     313                 :            :   // If velocity and acceleration are in the same direction -> no check; continue if 0 though
     314         [ -  + ]:         15 :   if (Real{} < (control.long_accel_mps2 * velocity)) {
     315                 :          0 :     return state.gear;
     316                 :            :   }
     317                 :            :   // Check if commanded acceleration will switch your sign
     318                 :            :   const auto dv =
     319                 :            :     control.long_accel_mps2 *
     320                 :         15 :     std::chrono::duration_cast<std::chrono::duration<Real>>(m_config.time_step()).count();
     321                 :         15 :   const auto v_next = dv + velocity;
     322         [ +  + ]:         15 :   const auto accel_switches_sign = Real{} > (velocity * v_next);
     323                 :            :   // Nonzero velocity and acceleration doesn't switch sign -> stay as is
     324                 :            :   constexpr auto EPS = std::numeric_limits<Real>::epsilon();
     325   [ +  +  +  + ]:         15 :   if (!comp::abs_eq_zero(velocity, EPS) && (!accel_switches_sign)) {
     326                 :          2 :     return state.gear;
     327                 :            :   }
     328                 :            :   // Zero velocity -> any acceleration should be a gear shift
     329                 :            :   // Return drive or reverse according to acceleration sign
     330         [ +  + ]:         13 :   return (control.long_accel_mps2 > Real{}) ? VSC::GEAR_DRIVE : VSC::GEAR_REVERSE;
     331                 :            : }
     332                 :            : 
     333                 :            : ////////////////////////////////////////////////////////////////////////////////
     334                 :        136 : BasicControlCommand SafetyStateMachine::clamp(BasicControlCommand in) const
     335                 :            : {
     336                 :            :   auto warn = false;
     337         [ +  + ]:        272 :   warn = m_config.accel_limits().clamp_warn(in.long_accel_mps2) || warn;
     338   [ +  +  +  + ]:        272 :   warn = m_config.front_wheel_limits().clamp_warn(in.front_wheel_angle_rad) || warn;
     339                 :            :   if (warn) {
     340                 :          5 :     m_reports.emplace_back(StateMachineReport::CLAMP_PAST_THRESHOLD);
     341                 :            :   }
     342                 :        136 :   return in;
     343                 :            : }
     344                 :            : 
     345                 :            : ////////////////////////////////////////////////////////////////////////////////
     346                 :        113 : void SafetyStateMachine::cache_state_change_request(const VSC & in)
     347                 :            : {
     348                 :        113 :   const auto stamp = ::time_utils::from_message(in.stamp);
     349                 :            :   // States
     350                 :            :   const auto update_request = [stamp](auto no_command, auto & command, auto state, auto & request) {
     351   [ +  -  +  -  :        111 :       if ((no_command != command) && (command != state)) {
          +  -  +  +  -  
                      - ]
     352                 :        109 :         request = {command, stamp};
     353                 :            :       }
     354                 :        113 :     };
     355         [ +  + ]:        113 :   update_request(WipersCommand::NO_COMMAND, in.wiper, m_state.wiper, m_requests.wiper);
     356         [ +  + ]:        113 :   update_request(VSC::BLINKER_NO_COMMAND, in.blinker, m_state.blinker, m_requests.blinker);
     357         [ +  + ]:        113 :   update_request(VSC::GEAR_NO_COMMAND, in.gear, m_state.gear, m_requests.gear);
     358                 :            :   update_request(
     359         [ +  + ]:        113 :     HeadlightsCommand::NO_COMMAND, in.headlight, m_state.headlight,
     360                 :            :     m_requests.headlight);
     361         [ -  + ]:        113 :   update_request(VSC::MODE_NO_COMMAND, in.mode, m_state.mode, m_requests.mode);
     362                 :            :   // Flags
     363                 :            :   const auto update_flag_request = [stamp](auto command, auto state, auto & request) -> void {
     364                 :        226 :       if (command != state) {
     365                 :          0 :         request = {command, stamp};
     366                 :            :       }
     367                 :            :     };
     368         [ -  + ]:        113 :   update_flag_request(in.horn, m_state.horn, m_requests.horn);
     369         [ -  + ]:        113 :   update_flag_request(in.hand_brake, m_state.hand_brake, m_requests.hand_brake);
     370                 :        113 : }
     371                 :            : 
     372                 :            : ////////////////////////////////////////////////////////////////////////////////
     373                 :       1195 : void SafetyStateMachine::check_state_change(const StateReport & in)
     374                 :            : {
     375                 :       1195 :   auto timeout = false;
     376                 :       1195 :   const auto stamp = ::time_utils::from_message(in.stamp) - m_config.state_transition_timeout();
     377                 :            :   // Check states
     378                 :            :   const auto check_state = [&timeout, stamp](auto & request, auto state, auto no_command) -> void {
     379                 :       5975 :       if (no_command == request.value) {
     380                 :            :         return;
     381                 :            :       }
     382   [ -  +  -  +  :         56 :       if (request.value == state) {
          -  +  -  +  -  
                      - ]
     383                 :          0 :         request = {no_command, decltype(stamp)::min()};
     384                 :            :       }
     385   [ +  -  +  -  :         56 :       if (stamp > request.stamp) {
          +  -  +  -  -  
                      - ]
     386                 :         56 :         timeout = true;
     387                 :            :       }
     388                 :            :     };
     389         [ +  + ]:       1195 :   check_state(m_requests.gear, in.gear, VSC::GEAR_NO_COMMAND);
     390         [ +  + ]:       1195 :   check_state(m_requests.blinker, in.blinker, VSC::BLINKER_NO_COMMAND);
     391         [ +  + ]:       1195 :   check_state(m_requests.wiper, in.wiper, WipersCommand::NO_COMMAND);
     392         [ +  + ]:       1195 :   check_state(m_requests.headlight, in.headlight, HeadlightsCommand::NO_COMMAND);
     393         [ -  + ]:       1195 :   check_state(m_requests.mode, in.mode, VSC::MODE_NO_COMMAND);
     394                 :            :   // Check flags
     395                 :            :   const auto check_flag = [&timeout, stamp](auto request, auto state) -> void {
     396                 :       2390 :       if (request.value == state) {
     397                 :            :         return;
     398                 :            :       }
     399   [ #  #  #  # ]:          0 :       if (stamp > request.stamp) {
     400                 :          0 :         timeout = true;
     401                 :            :       }
     402                 :            :     };
     403                 :            :   //lint -save -e523 NOLINT false positive: lambda affects timeout which is reference captured
     404         [ -  + ]:       1195 :   check_flag(m_requests.horn, in.horn);
     405         [ -  + ]:       1195 :   check_flag(m_requests.hand_brake, in.hand_brake);
     406                 :            :   //lint -restore NOLINT
     407                 :            :   // Warn on timeout
     408         [ +  + ]:       1195 :   if (timeout) {
     409                 :         47 :     m_reports.emplace_back(StateMachineReport::STATE_TRANSITION_TIMEOUT);
     410                 :            :   }
     411                 :       1195 : }
     412                 :            : 
     413                 :            : ////////////////////////////////////////////////////////////////////////////////
     414                 :        113 : SafetyStateMachine::VSC SafetyStateMachine::sanitize(const VSC & msg) const
     415                 :            : {
     416                 :            :   auto did_sanitize = false;
     417                 :        113 :   VSC ret{msg};
     418                 :            :   // Headlights
     419         [ +  + ]:        113 :   switch (msg.headlight) {
     420                 :            :     case HeadlightsCommand::NO_COMMAND:
     421                 :            :     case HeadlightsCommand::DISABLE:
     422                 :            :     case HeadlightsCommand::ENABLE_LOW:
     423                 :            :     case HeadlightsCommand::ENABLE_HIGH:
     424                 :            :       break;
     425                 :          2 :     default:
     426                 :            :       did_sanitize = true;
     427                 :            :       ret.headlight = HeadlightsCommand::NO_COMMAND;
     428                 :          2 :       break;
     429                 :            :   }
     430                 :            :   // Blinker
     431         [ +  + ]:        113 :   switch (msg.blinker) {
     432                 :            :     case VSC::BLINKER_NO_COMMAND:
     433                 :            :     case VSC::BLINKER_OFF:
     434                 :            :     case VSC::BLINKER_LEFT:
     435                 :            :     case VSC::BLINKER_RIGHT:
     436                 :            :     case VSC::BLINKER_HAZARD:
     437                 :            :       break;
     438                 :          2 :     default:
     439                 :            :       did_sanitize = true;
     440                 :            :       ret.blinker = VSC::BLINKER_NO_COMMAND;
     441                 :          2 :       break;
     442                 :            :   }
     443                 :            :   // Wipers
     444         [ +  + ]:        113 :   switch (msg.wiper) {
     445                 :            :     case WipersCommand::ENABLE_LOW:
     446                 :            :     case WipersCommand::ENABLE_HIGH:
     447                 :            :     case WipersCommand::DISABLE:
     448                 :            :     case WipersCommand::ENABLE_CLEAN:
     449                 :            :     case WipersCommand::NO_COMMAND:
     450                 :            :       break;
     451                 :          2 :     default:
     452                 :            :       did_sanitize = true;
     453                 :            :       ret.wiper = WipersCommand::NO_COMMAND;
     454                 :          2 :       break;
     455                 :            :   }
     456                 :            :   // Gear
     457         [ +  + ]:        113 :   switch (msg.gear) {
     458                 :            :     case VSC::GEAR_NO_COMMAND:
     459                 :            :     case VSC::GEAR_DRIVE:
     460                 :            :     case VSC::GEAR_PARK:
     461                 :            :     case VSC::GEAR_REVERSE:
     462                 :            :     case VSC::GEAR_NEUTRAL:
     463                 :            :     case VSC::GEAR_LOW:
     464                 :            :       break;
     465                 :          2 :     default:
     466                 :            :       did_sanitize = true;
     467                 :            :       ret.gear = VSC::GEAR_NO_COMMAND;
     468                 :          2 :       break;
     469                 :            :   }
     470                 :            :   // Mode
     471         [ +  + ]:        113 :   switch (msg.mode) {
     472                 :            :     case VSC::MODE_NO_COMMAND:
     473                 :            :     case VSC::MODE_AUTONOMOUS:
     474                 :            :     case VSC::MODE_MANUAL:
     475                 :            :       break;
     476                 :            :     default:
     477                 :            :       did_sanitize = true;
     478                 :            :       ret.mode = VSC::MODE_NO_COMMAND;
     479                 :            :       break;
     480                 :            :   }
     481                 :            : 
     482         [ +  + ]:        111 :   if (did_sanitize) {
     483                 :          6 :     m_reports.emplace_back(StateMachineReport::BAD_STATE);
     484                 :            :   }
     485                 :            : 
     486                 :        113 :   return ret;
     487                 :            : }
     488                 :            : 
     489                 :            : }  // namespace vehicle_interface
     490                 :            : }  // namespace drivers
     491                 :            : }  // namespace autoware

Generated by: LCOV version 1.14