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:");
58 ESP_LOGCONFIG(TAG,
" Tracking Mode: %s",
62 ESP_LOGCONFIG(TAG,
" Throttle: %" PRIu32
"ms", this->
throttle_);
67#ifdef USE_BINARY_SENSOR
70 for (uint8_t i = 0; i < MAX_TARGETS; i++) {
71 ESP_LOGCONFIG(TAG,
" Target %d:", i + 1);
73 LOG_SENSOR(
" ",
"X", this->
targets_[i].
x);
74 LOG_SENSOR(
" ",
"Y", this->
targets_[i].
y);
76 LOG_SENSOR(
" ",
"Distance", this->
targets_[i].distance);
78 LOG_SENSOR(
" ",
"Angle", this->
targets_[i].angle);
80#ifdef USE_BINARY_SENSOR
91 size_t to_read = std::min(avail,
sizeof(buf));
96 for (
size_t i = 0; i < to_read; i++) {
97 uint8_t
byte = buf[i];
98 ESP_LOGVV(TAG,
"Received byte: 0x%02X, buffer_pos: %d",
byte, this->
buffer_pos_);
103 this->
buffer_[this->buffer_pos_++] = byte;
104 }
else if (
byte == FRAME_HEADER[0]) {
107 this->buffer_pos_ = 1;
109 this->buffer_pos_ = 0;
120 if (this->
buffer_[FRAME_SIZE - 2] == FRAME_FOOTER[0] && this->
buffer_[FRAME_SIZE - 1] == FRAME_FOOTER[1]) {
123 ESP_LOGW(TAG,
"Invalid frame footer: 0x%02X 0x%02X (expected 0x55 0xCC)", this->
buffer_[FRAME_SIZE - 2],
124 this->
buffer_[FRAME_SIZE - 1]);
142 uint8_t target_count = 0;
144 for (uint8_t i = 0; i < MAX_TARGETS; i++) {
147 uint8_t offset = FRAME_HEADER_SIZE + (i * TARGET_DATA_SIZE);
150 uint8_t x_low = this->
buffer_[offset + 0];
151 uint8_t x_high = this->
buffer_[offset + 1];
152 uint8_t y_low = this->
buffer_[offset + 2];
153 uint8_t y_high = this->
buffer_[offset + 3];
154 uint8_t speed_low = this->
buffer_[offset + 4];
155 uint8_t speed_high = this->
buffer_[offset + 5];
156 uint8_t res_low = this->
buffer_[offset + 6];
157 uint8_t res_high = this->
buffer_[offset + 7];
160 int16_t
x = decode_value(x_low, x_high);
161 int16_t
y = decode_value(y_low, y_high);
162 int16_t
speed = decode_value(speed_low, speed_high);
163 uint16_t
resolution = (res_high << 8) | res_low;
168 bool has_position = (
x != 0 ||
y != 0);
169 bool has_valid_speed = is_speed_valid(
speed);
170 bool target_present = has_position && has_valid_speed;
171 if (target_present) {
179#ifdef USE_BINARY_SENSOR
192#ifdef USE_BINARY_SENSOR
205 if (target.
x !=
nullptr) {
210 if (target.
y !=
nullptr) {
215 if (target.
speed !=
nullptr) {
235 if (target.
angle !=
nullptr) {
237 float angle = std::atan2(
static_cast<float>(
x),
static_cast<float>(
y)) * 180.0f / std::numbers::pi_v<float>;
248 this->
write_array(CMD_FRAME_HEADER,
sizeof(CMD_FRAME_HEADER));
251 uint16_t
len = 2 + data_len;
260 if (data !=
nullptr && data_len > 0) {
265 this->
write_array(CMD_FRAME_FOOTER,
sizeof(CMD_FRAME_FOOTER));
267 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