Collision detection on transmit (#31)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Marius Muja 2023-07-07 17:23:26 -07:00 committed by GitHub
parent bd36a7e6a3
commit 38629aac52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 19 deletions

View File

@ -66,6 +66,11 @@ namespace ratgdo {
void RATGDOComponent::loop() void RATGDOComponent::loop()
{ {
if (this->transmit_pending_) {
if (!this->transmit_packet()) {
return;
}
}
this->obstruction_loop(); this->obstruction_loop();
this->gdo_state_loop(); this->gdo_state_loop();
} }
@ -167,7 +172,7 @@ namespace ratgdo {
// this->obstruction_state = static_cast<ObstructionState>((byte1 >> 6) & 1); // this->obstruction_state = static_cast<ObstructionState>((byte1 >> 6) & 1);
if (door_state == DoorState::CLOSED && door_state != prev_door_state) { if (door_state == DoorState::CLOSED && door_state != prev_door_state) {
this->transmit(Command::GET_OPENINGS); this->send_command(Command::GET_OPENINGS);
} }
ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s", ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s",
@ -204,7 +209,7 @@ namespace ratgdo {
} else if (cmd == Command::MOTION) { } else if (cmd == Command::MOTION) {
this->motion_state = MotionState::DETECTED; this->motion_state = MotionState::DETECTED;
if (*this->light_state == LightState::OFF) { if (*this->light_state == LightState::OFF) {
this->transmit(Command::GET_STATUS); this->send_command(Command::GET_STATUS);
} }
ESP_LOGD(TAG, "Motion: %s", MotionState_to_string(*this->motion_state)); ESP_LOGD(TAG, "Motion: %s", MotionState_to_string(*this->motion_state));
} else if (cmd == Command::SET_TTC) { } else if (cmd == Command::SET_TTC) {
@ -368,12 +373,12 @@ namespace ratgdo {
void RATGDOComponent::query_status() void RATGDOComponent::query_status()
{ {
transmit(Command::GET_STATUS); send_command(Command::GET_STATUS);
} }
void RATGDOComponent::query_openings() void RATGDOComponent::query_openings()
{ {
transmit(Command::GET_OPENINGS); send_command(Command::GET_OPENINGS);
} }
/************************* DOOR COMMUNICATION *************************/ /************************* DOOR COMMUNICATION *************************/
@ -385,18 +390,39 @@ namespace ratgdo {
* The opener requires a specific duration low/high pulse before it will accept * The opener requires a specific duration low/high pulse before it will accept
* a message * a message
*/ */
void RATGDOComponent::transmit(Command command, uint32_t data, bool increment) void RATGDOComponent::send_command(Command command, uint32_t data, bool increment)
{ {
WirePacket tx_packet; if (!this->transmit_pending_) { // have an untransmitted packet
this->encode_packet(command, data, increment, this->tx_packet_);
} else {
// unlikely this would happed, we're ensuring any pending packet
// is transmitted each loop before doing anyting else
ESP_LOGW(TAG, "Have untransmitted packet, ignoring command: %s", Command_to_string(command));
}
this->transmit_packet();
}
bool RATGDOComponent::transmit_packet()
{
auto now = micros64();
while (micros64() - now < 1300) {
if (this->input_gdo_pin_->digital_read()) {
ESP_LOGD(TAG, "Collision detected, waiting to send packet");
this->transmit_pending_ = true;
return false;
}
delayMicroseconds(200);
}
this->encode_packet(command, data, increment, tx_packet);
this->output_gdo_pin_->digital_write(true); // pull the line high for 1305 micros so the this->output_gdo_pin_->digital_write(true); // pull the line high for 1305 micros so the
// door opener responds to the message // door opener responds to the message
delayMicroseconds(1305); delayMicroseconds(1305);
this->output_gdo_pin_->digital_write(false); // bring the line low this->output_gdo_pin_->digital_write(false); // bring the line low
delayMicroseconds(1260); // "LOW" pulse duration before the message start delayMicroseconds(1260); // "LOW" pulse duration before the message start
this->sw_serial_.write(tx_packet, PACKET_LENGTH); this->sw_serial_.write(this->tx_packet_, PACKET_LENGTH);
this->transmit_pending_ = false;
return true;
} }
void RATGDOComponent::sync() void RATGDOComponent::sync()
@ -414,7 +440,7 @@ namespace ratgdo {
ESP_LOGD(TAG, "Triggering sync failed actions."); ESP_LOGD(TAG, "Triggering sync failed actions.");
this->sync_failed = true; this->sync_failed = true;
}; };
this->transmit(Command::GET_OPENINGS); this->send_command(Command::GET_OPENINGS);
return RetryResult::RETRY; return RetryResult::RETRY;
} }
} else { } else {
@ -422,7 +448,7 @@ namespace ratgdo {
ESP_LOGD(TAG, "Triggering sync failed actions."); ESP_LOGD(TAG, "Triggering sync failed actions.");
this->sync_failed = true; this->sync_failed = true;
}; };
this->transmit(Command::GET_STATUS); this->send_command(Command::GET_STATUS);
return RetryResult::RETRY; return RetryResult::RETRY;
} }
}, },
@ -556,48 +582,48 @@ namespace ratgdo {
{ {
data |= (1 << 16); // button 1 ? data |= (1 << 16); // button 1 ?
data |= (1 << 8); // button press data |= (1 << 8); // button press
this->transmit(Command::OPEN, data, false); this->send_command(Command::OPEN, data, false);
set_timeout(100, [=] { set_timeout(100, [=] {
auto data2 = data & ~(1 << 8); // button release auto data2 = data & ~(1 << 8); // button release
this->transmit(Command::OPEN, data2); this->send_command(Command::OPEN, data2);
}); });
} }
void RATGDOComponent::light_on() void RATGDOComponent::light_on()
{ {
this->light_state = LightState::ON; this->light_state = LightState::ON;
this->transmit(Command::LIGHT, data::LIGHT_ON); this->send_command(Command::LIGHT, data::LIGHT_ON);
} }
void RATGDOComponent::light_off() void RATGDOComponent::light_off()
{ {
this->light_state = LightState::OFF; this->light_state = LightState::OFF;
this->transmit(Command::LIGHT, data::LIGHT_OFF); this->send_command(Command::LIGHT, data::LIGHT_OFF);
} }
void RATGDOComponent::toggle_light() void RATGDOComponent::toggle_light()
{ {
this->light_state = light_state_toggle(*this->light_state); this->light_state = light_state_toggle(*this->light_state);
this->transmit(Command::LIGHT, data::LIGHT_TOGGLE); this->send_command(Command::LIGHT, data::LIGHT_TOGGLE);
} }
// Lock functions // Lock functions
void RATGDOComponent::lock() void RATGDOComponent::lock()
{ {
this->lock_state = LockState::LOCKED; this->lock_state = LockState::LOCKED;
this->transmit(Command::LOCK, data::LOCK_ON); this->send_command(Command::LOCK, data::LOCK_ON);
} }
void RATGDOComponent::unlock() void RATGDOComponent::unlock()
{ {
this->lock_state = LockState::UNLOCKED; this->lock_state = LockState::UNLOCKED;
this->transmit(Command::LOCK, data::LOCK_OFF); this->send_command(Command::LOCK, data::LOCK_OFF);
} }
void RATGDOComponent::toggle_lock() void RATGDOComponent::toggle_lock()
{ {
this->lock_state = lock_state_toggle(*this->lock_state); this->lock_state = lock_state_toggle(*this->lock_state);
this->transmit(Command::LOCK, data::LOCK_TOGGLE); this->send_command(Command::LOCK, data::LOCK_TOGGLE);
} }
LightState RATGDOComponent::get_light_state() const LightState RATGDOComponent::get_light_state() const

View File

@ -131,7 +131,8 @@ namespace ratgdo {
void gdo_state_loop(); void gdo_state_loop();
uint16_t decode_packet(const WirePacket& packet); uint16_t decode_packet(const WirePacket& packet);
void obstruction_loop(); void obstruction_loop();
void transmit(Command command, uint32_t data = 0, bool increment = true); void send_command(Command command, uint32_t data = 0, bool increment = true);
bool transmit_packet();
void encode_packet(Command command, uint32_t data, bool increment, WirePacket& packet); void encode_packet(Command command, uint32_t data, bool increment, WirePacket& packet);
void print_packet(const WirePacket& packet) const; void print_packet(const WirePacket& packet) const;
@ -183,6 +184,10 @@ namespace ratgdo {
void subscribe_sync_failed(std::function<void(bool)>&& f); void subscribe_sync_failed(std::function<void(bool)>&& f);
protected: protected:
// tx data
bool transmit_pending_ {false};
WirePacket tx_packet_;
RATGDOStore isr_store_ {}; RATGDOStore isr_store_ {};
SoftwareSerial sw_serial_; SoftwareSerial sw_serial_;