11static const char *
const TAG =
"rd03d";
14static constexpr uint32_t SETUP_TIMEOUT_MS = 100;
17static constexpr uint8_t FRAME_HEADER[] = {0xAA, 0xFF, 0x03, 0x00};
18static constexpr uint8_t FRAME_FOOTER[] = {0x55, 0xCC};
21static constexpr uint8_t CMD_FRAME_HEADER[] = {0xFD, 0xFC, 0xFB, 0xFA};
22static constexpr uint8_t CMD_FRAME_FOOTER[] = {0x04, 0x03, 0x02, 0x01};
25static constexpr uint16_t CMD_SINGLE_TARGET = 0x0080;
26static constexpr uint16_t CMD_MULTI_TARGET = 0x0090;
30static constexpr int16_t SPEED_SENTINEL_248 = 248;
31static constexpr int16_t SPEED_SENTINEL_256 = 256;
35static constexpr int16_t decode_value(uint8_t low_byte, uint8_t high_byte) {
36 int16_t value = ((high_byte & 0x7F) << 8) | low_byte;
37 if ((high_byte & 0x80) == 0) {
45static constexpr bool is_speed_valid(int16_t
speed) {
47 return speed != 0 && abs_speed != SPEED_SENTINEL_248 && abs_speed != SPEED_SENTINEL_256;
51 ESP_LOGCONFIG(TAG,
"Setting up RD-03D...");
56 ESP_LOGCONFIG(TAG,
"RD-03D:");
59 TAG,
" Tracking Mode: %s",
63 ESP_LOGCONFIG(TAG,
" Throttle: %" PRIu32
"ms", this->
throttle_);
68#ifdef USE_BINARY_SENSOR
71 for (uint8_t i = 0; i < MAX_TARGETS; i++) {
72 ESP_LOGCONFIG(TAG,
" Target %d:", i + 1);
74 LOG_SENSOR(
" ",
"X", this->
targets_[i].
x);
75 LOG_SENSOR(
" ",
"Y", this->
targets_[i].
y);
77 LOG_SENSOR(
" ",
"Distance", this->
targets_[i].distance);
79 LOG_SENSOR(
" ",
"Angle", this->
targets_[i].angle);
81#ifdef USE_BINARY_SENSOR
92 size_t to_read = std::min(avail,
sizeof(buf));
97 for (
size_t i = 0; i < to_read; i++) {
98 uint8_t
byte = buf[i];
99 ESP_LOGVV(TAG,
"Received byte: 0x%02X, buffer_pos: %d",
byte, this->
buffer_pos_);
104 this->
buffer_[this->buffer_pos_++] = byte;
105 }
else if (
byte == FRAME_HEADER[0]) {
108 this->buffer_pos_ = 1;
110 this->buffer_pos_ = 0;
121 if (this->
buffer_[FRAME_SIZE - 2] == FRAME_FOOTER[0] && this->
buffer_[FRAME_SIZE - 1] == FRAME_FOOTER[1]) {
124 ESP_LOGW(TAG,
"Invalid frame footer: 0x%02X 0x%02X (expected 0x55 0xCC)", this->
buffer_[FRAME_SIZE - 2],
125 this->
buffer_[FRAME_SIZE - 1]);
143 uint8_t target_count = 0;
145 for (uint8_t i = 0; i < MAX_TARGETS; i++) {
148 uint8_t offset = FRAME_HEADER_SIZE + (i * TARGET_DATA_SIZE);
151 uint8_t x_low = this->
buffer_[offset + 0];
152 uint8_t x_high = this->
buffer_[offset + 1];
153 uint8_t y_low = this->
buffer_[offset + 2];
154 uint8_t y_high = this->
buffer_[offset + 3];
155 uint8_t speed_low = this->
buffer_[offset + 4];
156 uint8_t speed_high = this->
buffer_[offset + 5];
157 uint8_t res_low = this->
buffer_[offset + 6];
158 uint8_t res_high = this->
buffer_[offset + 7];
161 int16_t
x = decode_value(x_low, x_high);
162 int16_t
y = decode_value(y_low, y_high);
163 int16_t
speed = decode_value(speed_low, speed_high);
164 uint16_t
resolution = (res_high << 8) | res_low;
169 bool has_position = (
x != 0 ||
y != 0);
170 bool has_valid_speed = is_speed_valid(
speed);
171 bool target_present = has_position && has_valid_speed;
172 if (target_present) {
180#ifdef USE_BINARY_SENSOR
193#ifdef USE_BINARY_SENSOR
206 if (target.
x !=
nullptr) {
211 if (target.
y !=
nullptr) {
216 if (target.
speed !=
nullptr) {
236 if (target.
angle !=
nullptr) {
238 float angle = std::atan2(
static_cast<float>(
x),
static_cast<float>(
y)) * 180.0f / std::numbers::pi_v<float>;
249 this->
write_array(CMD_FRAME_HEADER,
sizeof(CMD_FRAME_HEADER));
252 uint16_t
len = 2 + data_len;
261 if (data !=
nullptr && data_len > 0) {
266 this->
write_array(CMD_FRAME_FOOTER,
sizeof(CMD_FRAME_FOOTER));
268 ESP_LOGD(TAG,
"Sent command 0x%04X with %d bytes of data", command, data_len);
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
void publish_state(bool new_state)
Publish a new state to the front-end.
optional< TrackingMode > tracking_mode_
std::array< TargetSensor, MAX_TARGETS > targets_
void dump_config() override
void send_command_(uint16_t command, const uint8_t *data=nullptr, uint8_t data_len=0)
uint32_t last_publish_time_
binary_sensor::BinarySensor * target_binary_sensor_
std::array< uint8_t, FRAME_SIZE > buffer_
void publish_target_(uint8_t target_num, int16_t x, int16_t y, int16_t speed, uint16_t resolution)
std::array< binary_sensor::BinarySensor *, MAX_TARGETS > target_presence_
sensor::Sensor * target_count_sensor_
void publish_state(float state)
Publish a new state to the front-end.
optional< std::array< uint8_t, N > > read_array()
void write_byte(uint8_t data)
void write_array(const uint8_t *data, size_t len)
uint32_t IRAM_ATTR HOT millis()
sensor::Sensor * resolution
sensor::Sensor * distance