Skip to content

Commit

Permalink
Fix possible lock-up while reading UART (#6)
Browse files Browse the repository at this point in the history
* Add sensor unavailable state to Zones

* Use uint32_t for timestamps, Fix possible lock-up while reading UART
  • Loading branch information
TillFleisch authored Feb 14, 2024
1 parent 57b2009 commit 5504e5e
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 22 deletions.
48 changes: 34 additions & 14 deletions components/LD2450/LD2450.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ namespace esphome::ld2450
else
{
command_queue_.erase(command_queue_.begin());
command_send_retries_ = 0;
}
command_send_retries_ = 0;
ESP_LOGW(TAG, "Sending command timed out! Is the sensor connected?");
}
else
Expand All @@ -132,36 +132,41 @@ namespace esphome::ld2450
{
// Inject leave config command after clearing the queue
command_queue_.push_back({COMMAND_LEAVE_CONFIG, 0x00});
command_send_retries_ = 0;
}

// Skip stream until start of message and parse header
while (!peek_status_ && available() >= 4)
if (!peek_status_ && available() >= 4)
{
// Try to read the header and abort on mismatch
const uint8_t *header;
bool skip = false;
uint8_t target;
if (peek() == update_header[0])
uint8_t message_type;
uint8_t first_byte = read();
if (first_byte == update_header[0])
{
header = update_header;
target = 1;
message_type = 1;
}
else
else if (first_byte == config_header[0])
{
header = config_header;
target = 2;
message_type = 2;
}
else
{
skip = true;
}

for (int i = 0; i < 4 && !skip; i++)
for (int i = 1; i < 4 && !skip; i++)
{
if (read() != header[i])
skip = true;
}
if (skip)
continue;

// Flag successful header reading
peek_status_ = target;
if (!skip)
// Flag successful header reading
peek_status_ = message_type;
}

if (peek_status_ == 1 && available() >= 28)
Expand Down Expand Up @@ -201,10 +206,25 @@ namespace esphome::ld2450
peek_status_ = 0;
}
}

if (sensor_available_ && millis() - last_message_received_ > SENSOR_UNAVAILABLE_TIMEOUT)
{
sensor_available_ = false;

ESP_LOGE(TAG, "LD2450-Sensor stopped sending updates!");

// Update zones and related components
for (Zone *zone : zones_)
{
zone->update(targets_, sensor_available_);
}
}
}

void LD2450::process_message(uint8_t *msg, int len)
{
sensor_available_ = true;
last_message_received_ = millis();
for (int i = 0; i < 3; i++)
{
int offset = 8 * i;
Expand Down Expand Up @@ -251,7 +271,7 @@ namespace esphome::ld2450
// Update zones and related components
for (Zone *zone : zones_)
{
zone->update(targets_);
zone->update(targets_, sensor_available_);
}
}

Expand Down Expand Up @@ -396,7 +416,7 @@ namespace esphome::ld2450

// Write message length
write(static_cast<uint8_t>(len));
write(static_cast<uint8_t>(len << 8));
write(static_cast<uint8_t>(len >> 8));

// Write message content
write_array(msg, len);
Expand Down
21 changes: 19 additions & 2 deletions components/LD2450/LD2450.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
#include "esphome/components/button/button.h"
#endif

#define COMMAND_MAX_RETRIES 5
#define SENSOR_UNAVAILABLE_TIMEOUT 1000

#define COMMAND_MAX_RETRIES 10
#define COMMAND_RETRY_DELAY 100

#define COMMAND_ENTER_CONFIG 0xFF
Expand Down Expand Up @@ -215,6 +217,15 @@ namespace esphome::ld2450
return targets_[i];
}

/**
* @brief Gets the state of the connected sensor
* @return True if the sensor is connected and communicating, False otherwise
*/
bool is_sensor_available()
{
return sensor_available_;
}

/**
* @brief Reads and logs the sensors version number.
*/
Expand Down Expand Up @@ -315,11 +326,17 @@ namespace esphome::ld2450
/// @brief Indicated that the sensor is currently factory resetting
bool is_applying_changes_ = false;

/// @brief indicates if the sensor is communicating
bool sensor_available_ = false;

/// @brief Expected length of the configuration message
int configuration_message_length_ = 0;

/// @brief timestamp of the last message which was sent to the sensor
long command_last_sent_ = 0;
uint32_t command_last_sent_ = 0;

/// @brief timestamp of the last received message
uint32_t last_message_received_ = 0;

/// @brief Queue of commands to execute
std::vector<std::vector<uint8_t>> command_queue_;
Expand Down
6 changes: 3 additions & 3 deletions components/LD2450/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ namespace esphome::ld2450
* @brief Time since last last change in values.
* @return timestamp in milliseconds since start
*/
long get_last_change()
uint32_t get_last_change()
{
return last_change_;
}
Expand Down Expand Up @@ -206,10 +206,10 @@ namespace esphome::ld2450
bool fast_off_detection_ = false;

/// @brief time stamp of the last debug message which was sent.
long last_debug_message_ = 0;
uint32_t last_debug_message_ = 0;

/// @brief time of the last value change
long last_change_ = 0;
uint32_t last_change_ = 0;

/// @brief sensor reference of the x position sensor
PollingSensor *x_position_sensor_ = nullptr;
Expand Down
15 changes: 14 additions & 1 deletion components/LD2450/zone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,21 @@ namespace esphome::ld2450
#endif
}

void Zone::update(std::vector<Target *> &targets)
void Zone::update(std::vector<Target *> &targets, bool sensor_available)
{
if (!sensor_available)
{
#ifdef USE_BINARY_SENSOR
if (occupancy_binary_sensor_ != nullptr)
occupancy_binary_sensor_->publish_state(false);
#endif
#ifdef USE_SENSOR
if (target_count_sensor_ != nullptr)
target_count_sensor_->publish_state(NAN);
#endif
return;
}

if (polygon_.size() < 3)
return;

Expand Down
5 changes: 3 additions & 2 deletions components/LD2450/zone.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ namespace esphome::ld2450
/**
* @brief Updates sensors related to this zone.
* @param targets Reference to a vector of targets which will be used for calculation
* @param available True if the sensor is currently available, false otherwise
* */
void update(std::vector<Target *> &targets);
void update(std::vector<Target *> &targets, bool sensor_available);

/**
* Logs the Zone configuration.
Expand Down Expand Up @@ -142,6 +143,6 @@ namespace esphome::ld2450
int target_timeout_ = 5000;

/// @brief Map of targets which are currently tracked inside of this polygon with their last seen timestamp
std::map<Target *, long> tracked_targets_{};
std::map<Target *, uint32_t> tracked_targets_{};
};
} // namespace esphome::ld2450

0 comments on commit 5504e5e

Please sign in to comment.